home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 18 / CU Amiga Magazine's Super CD-ROM 18 (1997)(EMAP Images)(GB)[!][issue 1998-01].iso / CUCD / Programming / AmigaE / Src / Tools / EasyGUI / Source / EasyGUI.e next >
Encoding:
Text File  |  1997-10-09  |  58.5 KB  |  2,009 lines

  1. -> EasyGui.m, constructs fast nononsense font sensitive resizable gui's.
  2.  
  3. OPT MODULE, OSVERSION=37, PREPROCESS
  4.  
  5. -> Let only one of the following be defined:
  6.  
  7. ->#define EASYGUI_LITE
  8. #define EASYGUI_FULL
  9. ->#define EASYGUI_DEBUG
  10.  
  11.  
  12. -> This selects various components based on above choice.
  13. #ifndef EASYGUI_LITE
  14. #define EASY_KEYBOARD
  15. #ifdef EASYGUI_DEBUG
  16. #ifndef EASYGUI_FULL
  17. #define EASYGUI_FULL
  18. #endif
  19. #endif
  20. #ifdef EASYGUI_FULL
  21. #define EASY_APPWINDOW
  22. #define EASY_EXTRAS
  23. #endif
  24. #endif
  25.  
  26. -> This enables a descriptive message before an exception is raised.
  27. #ifdef EASYGUI_DEBUG
  28. #define RaiseX(x,l,s) myraise(x,l,s)
  29. MODULE 'tools/exceptions'
  30. #endif
  31. #ifndef EASYGUI_DEBUG
  32. #define RaiseX(x,l,s) Raise(x)
  33. #endif
  34.  
  35. MODULE 'gadtools',
  36.        'exec/libraries', 'exec/lists', 'exec/nodes', 'exec/ports',
  37.        'graphics/rastport', 'graphics/text',
  38.        'graphics/gfx', 'graphics/videocontrol', 'graphics/view',
  39.        'intuition/gadgetclass', 'intuition/imageclass', 'intuition/intuition',
  40.        'intuition/screens',
  41.        'libraries/gadtools',
  42.        'tools/textlen', 'amigalib/lists',
  43.        'utility/tagitem',
  44.        'utility'
  45.  
  46. #ifdef EASY_APPWINDOW
  47. MODULE 'wb', 'workbench/workbench'
  48. #endif
  49.  
  50. #ifdef EASY_KEYBOARD
  51. MODULE 'tools/ctype'
  52. #endif
  53.  
  54. DEF utilitybase  -> Redefine for privateness
  55.  
  56. #ifdef EASY_EXTRAS
  57. /************ multihandle ************/
  58. EXPORT OBJECT multihandle
  59.   sig
  60.   opencount
  61. PRIVATE
  62. #ifdef EASY_APPWINDOW
  63.   awport:PTR TO mp
  64. #endif
  65.   wndport:PTR TO mp
  66.   guis:lh
  67. ENDOBJECT
  68. #endif
  69.  
  70. -> The offset of the `link' node in a guihandle.  Used for getting
  71. -> back to the guihandle from the node in the list.
  72. CONST GH_LINK_OFFSET=16
  73.  
  74. /************ guihandle ************/
  75. EXPORT OBJECT guihandle
  76.   -> Window, Signal Mask (not Bit), Info
  77.   wnd:PTR TO window,sig,info
  78. #ifdef EASY_EXTRAS
  79.   -> Multi-Window Handle
  80.   mh:PTR TO multihandle
  81. #endif
  82. PRIVATE
  83. #ifdef EASY_EXTRAS
  84.   -> Node for Linking GUIs in Multi-Window GUIs
  85.   link:ln
  86. #endif
  87.   -> Private Window Pointer (so that wnd is a flag for GUI validity, too)
  88.   pwnd:PTR TO window
  89.   -> Last Gadget, VisualInfo, Font, Font_uses_screen, GT_lib_is_open
  90.   gl:PTR TO gadget,visual,tattr:PTR TO textattr,ta_scr,gt_isopen
  91.   -> Gadget desc, Gadget list, Screen, Screen_is_WB
  92.   base:PTR TO g,glist,scr:PTR TO screen,is_wb
  93.   -> Min Width and Height, X and Y Offset Past Window Borders
  94.   xsize,ysize,xoff,yoff
  95.   -> Menus, Plugins
  96.   menus, plugins:PTR TO plugin
  97. #ifndef EASY_KEYBOARD
  98.   -> First String Gadget
  99.   firststr
  100. #endif
  101. #ifdef EASY_KEYBOARD
  102.   -> Map of Key to Gadget
  103.   keys[26]:ARRAY OF LONG
  104. #endif
  105. #ifdef EASY_APPWINDOW
  106.   -> AppWindow Port, AppWindow, WB_lib_is_open
  107.   awport:PTR TO mp,appwin,wb_isopen
  108. #endif
  109. #ifdef EASY_EXTRAS
  110.   -> Requester used for Blocking
  111.   req:PTR TO requester
  112. #endif
  113.   -> GUI X and Y, GUI Desc, Window Title, Menu Desc
  114.   x,y,gui,wtitle,awproc,newmenus
  115.   -> Window Port, OnClose Proc, Window Type, OnClean Proc
  116.   wndport:PTR TO mp,onclose,wtype,onclean
  117.   -> Hack to make menu selections safe
  118.   menuitem:PTR TO LONG
  119. #ifdef EASY_EXTRAS
  120.   -> Count of blockwin() calls
  121.   blockcnt
  122. #endif
  123. ENDOBJECT
  124.  
  125. -> Flag set for resizing constants.
  126. SET CRSZ_X, CRSZ_Y, UNCOND_X, UNCOND_Y
  127.  
  128. EXPORT CONST COND_RESIZEX=CRSZ_X, COND_RESIZEY=CRSZ_Y
  129. EXPORT CONST RESIZEX=COND_RESIZEX OR UNCOND_X, RESIZEY=COND_RESIZEY OR UNCOND_Y
  130.  
  131. CONST RESIZEXANDY=RESIZEX OR RESIZEY
  132.  
  133. -> Resize testing macros.
  134. #define DoesXResize(flag) ((flag) AND COND_RESIZEX)
  135. #define DoesYResize(flag) ((flag) AND COND_RESIZEY)
  136. #define DoesXUncond(flag) ((flag) AND RESIZEX=RESIZEX)
  137. #define DoesYUncond(flag) ((flag) AND RESIZEY=RESIZEY)
  138.  
  139. -> Gadget type constants.
  140. ->          0    1      2    3      4     5
  141. EXPORT ENUM ROWS,EQROWS,COLS,EQCOLS,BEVEL,BEVELR,
  142. ->       6      7     8       9     10 11    12      13     14    15  16   17
  143.          BUTTON,CHECK,INTEGER,LISTV,MX,CYCLE,PALETTE,SCROLL,SLIDE,STR,TEXT,NUM,
  144. ->       18      19     20  21     22    23     24      25
  145.          SBUTTON,PLUGIN,BAR,SPACEH,SPACE,SPACEV,RBUTTON,MAXGUI
  146.  
  147. -> ROWS...      BUTTON...   PALETTE...      SBUTTON...     RBUTTON...
  148. -> Mapping of gadget type to GT KIND.
  149. #define KINDTAB \
  150.   [0,0,0,0,0,0, 1,2,3,4,5,7,8,9,11,12,13,6, 1, 0, 0,0,0,0, 1,12]:CHAR
  151. -> Mapping of gadget type to number of required arguments.
  152. #define MINARGS \
  153.   [2,2,2,2,2,2, 3,5,5,9,6,4,7,7, 9, 6, 5,5, 3, 3, 1,1,1,1, 3,6]:CHAR
  154.  
  155. -> Constants to index gadget desc lists.
  156. EXPORT ENUM BEV_GUI=1,
  157.   BUT_ACT=1, BUT_TXT,  BUT_DATA, BUT_KEY,  BUT_APPW, BUT_DIS,
  158.   CHK_ACT=1, CHK_TXT,  CHK_VAL,  CHK_LEFT, CHK_DATA, CHK_KEY,  CHK_DIS,
  159.   INT_ACT=1, INT_TXT,  INT_VAL,  INT_REL,  INT_DATA, INT_KEY,  INT_DIS,
  160.   LST_ACT=1, LST_TXT,  LST_RELX, LST_RELY, LST_LIST, LST_RO,   LST_SHOW,
  161.              LST_CURR, LST_DATA, LST_KEY,  LST_APPW, LST_DIS,
  162.    MX_ACT=1,  MX_TXT,   MX_LIST,  MX_LEFT,  MX_CURR,  MX_DATA,  MX_KEY,
  163.               MX_DIS,
  164.   CYC_ACT=1, CYC_TXT,  CYC_LIST, CYC_CURR, CYC_DATA, CYC_KEY,  CYC_DIS,
  165.   PAL_ACT=1, PAL_TXT,  PAL_DEP,  PAL_RELX, PAL_RELY, PAL_CURR, PAL_DATA,
  166.              PAL_KEY,  PAL_DIS,
  167.   SCR_ACT=1, SCR_VERT, SCR_TOTL, SCR_TOP,  SCR_VIS,  SCR_REL,  SCR_DATA,
  168.              SCR_KEY,  SCR_DIS,
  169.   SLI_ACT=1, SLI_TXT,  SLI_VERT, SLI_MIN,  SLI_MAX,  SLI_CURR, SLI_REL,
  170.              SLI_FMT,  SLI_DATA, SLI_KEY,  SLI_DIS,
  171.   STR_ACT=1, STR_TXT,  STR_STR,  STR_MAX,  STR_REL,  STR_OVR,  STR_DATA,
  172.              STR_KEY,  STR_APPW, STR_DIS,
  173.   TXT_VAL=1, TXT_TXT,  TXT_BORD, TXT_REL,
  174.   NUM_VAL=1, NUM_TXT,  NUM_BORD, NUM_REL,
  175.   PLG_ACT=1, PLG_OBJ,  PLG_GT,   PLG_APPW
  176.  
  177. ENUM EG_TYPE=0, EG_ACT, EG_TXT
  178.  
  179. -> Test group type macros.
  180. #define IsRow(type)        ((type)<=EQROWS)
  181. #define IsCol(type)        ((type)>EQROWS)
  182. #define IsRowOrCol(type)   ((type)<BEVEL)
  183. #define IsBevel(type)      ((type)<BUTTON)
  184. #define IsGroup(type)      IsBevel(type)
  185. #define IsEqualGroup(type) (((type)=EQROWS) OR ((type)=EQCOLS))
  186.  
  187. -> Test space sizing macros.
  188. #define HasHSpace(type)    ((type)<=SPACE)
  189. #define HasVSpace(type)    ((type)>=SPACE)
  190. #define HSpace(type)       (IF HasHSpace(type) THEN RESIZEX ELSE 0)
  191. #define VSpace(type)       (IF HasVSpace(type) THEN RESIZEY ELSE 0)
  192. #define SpaceFlags(type)   (HSpace(type) OR VSpace(type))
  193.  
  194. -> Test button sizing macros.
  195. #define HasHButtSp(type)   ((type)>=SBUTTON)
  196. #define HasVButtSp(type)   ((type)=RBUTTON)
  197. #define HButtSp(type)      (IF HasHButtSp(type) THEN RESIZEX ELSE 0)
  198. #define VButtSp(type)      (IF HasVButtSp(type) THEN RESIZEY ELSE 0)
  199. #define ButtSpFlags(type)  (HButtSp(type) OR VButtSp(type))
  200.  
  201. CONST SP=2,YSP=3            -> very basic spacing (Y=nonsense!?!)
  202. CONST XSPACING=YSP,YSPACING=SP,   -> basic spacing between gadgets
  203.       SIDESPACE=YSP,TOPSPACE=SP,  -> spacing to window border
  204.       BUTXSPACE=16,BUTYSPACE=6,   -> space around text in button (min)
  205.       BEVELXSPACE=4,BEVELYSPACE=3,  -> between bevelbox and inner gadgets
  206.       MXSPACE=2,CHECKSPACE=2        -> between two mx and check gads
  207.  
  208. EXPORT ENUM WTYPE_NOBORDER, WTYPE_BASIC, WTYPE_NOSIZE, WTYPE_SIZE
  209.  
  210. -> Window flags.
  211. CONST WIN_FBASIC=WFLG_ACTIVATE OR WFLG_NEWLOOKMENUS
  212. CONST WIN_FNOBORD=WFLG_BORDERLESS OR WIN_FBASIC
  213. CONST WIN_FNOSIZE=WIN_FBASIC OR WFLG_DRAGBAR OR WFLG_DEPTHGADGET OR
  214.                   WFLG_CLOSEGADGET
  215. CONST WIN_FSIZE=WIN_FNOSIZE OR WFLG_SIZEBBOTTOM OR WFLG_SIZEGADGET
  216.  
  217. -> Gadget click IDCMP.
  218. CONST GAD_IDCMP=IDCMP_GADGETDOWN OR IDCMP_GADGETUP OR IDCMP_MOUSEMOVE
  219.  
  220. -> Window IDMCP (without NEWSIZE).
  221. CONST WIN_IDCMP_NS=GAD_IDCMP OR IDCMP_REFRESHWINDOW OR IDCMP_MOUSEBUTTONS OR
  222.                    IDCMP_MENUPICK OR IDCMP_CLOSEWINDOW OR IDCMP_RAWKEY OR
  223.                    IDCMP_ACTIVEWINDOW OR IDCMP_INACTIVEWINDOW OR
  224.                    IDCMP_INTUITICKS OR IDCMP_CHANGEWINDOW OR IDCMP_VANILLAKEY
  225.  
  226. -> Window IDMCP (with NEWSIZE).
  227. CONST WIN_IDCMP=IDCMP_NEWSIZE OR WIN_IDCMP_NS
  228.  
  229. -> Message loop constants.
  230. CONST GUI_CONT=-1, GUI_QUIT=0
  231.  
  232. -> Action function test macro.
  233. #define IsActionFun(ret) (((ret)<0) OR ((ret)>1000))
  234.  
  235. -> Convert to unsigned INT.
  236. #define Unsigned(x) ((x) AND $FFFF)
  237.  
  238. -> System gadget aspect ratio macro.
  239. #define SysISize(flags) \
  240.         (IF (flags) AND SCREENHIRES THEN SYSISIZE_MEDRES ELSE SYSISIZE_LOWRES)
  241.  
  242. -> Gadget information extraction macros.
  243. #define GadLongInt(gad) (gad.specialinfo::stringinfo.longint)
  244. #define GadString(gad)  (gad.specialinfo::stringinfo.buffer)
  245. #define IsChecked(gad)  ((gad.flags AND GFLG_SELECTED)<>0)
  246.  
  247. -> Constant to mark gadget has no mid-point.
  248. CONST NO_MID=-1
  249.  
  250. -> Gadget data (intermediate level).
  251. OBJECT g
  252.   -> Link, X, Y, Width, Height
  253.   next,x,y,xs,ys
  254.   -> Gadget Type, Gadget Desc, Flags, Mid-Point
  255.   type,list:PTR TO LONG,flags,mid
  256. ENDOBJECT
  257.  
  258. /************ plugin ************/
  259. EXPORT OBJECT plugin PRIVATE
  260.   -> Gadget Data, Link
  261.   base:PTR TO g, next:PTR TO plugin
  262. PUBLIC
  263.   -> X, Y, Width, Height
  264.   x:INT,y:INT,xs:INT,ys:INT
  265.   -> guihandle
  266.   gh:PTR TO guihandle
  267. ENDOBJECT
  268.  
  269. PROC min_size(ta,fontheight) OF plugin IS fontheight,fontheight
  270. PROC will_resize() OF plugin IS RESIZEXANDY
  271. PROC message_test(imsg:PTR TO intuimessage,win:PTR TO window) OF plugin IS FALSE
  272. PROC message_action(class,qual,code,win:PTR TO window) OF plugin IS FALSE
  273. PROC clear_render(win:PTR TO window) OF plugin IS EMPTY
  274.  
  275. PROC render(ta:PTR TO textattr,x,y,xs,ys,win:PTR TO window) OF plugin
  276.   fillbox(win.rport,1,x,y,x+xs-1,y+ys-1)
  277. ENDPROC
  278.  
  279. PROC appmessage(amsg,win:PTR TO window) OF plugin IS FALSE
  280. PROC gtrender(gl,vis,ta,x,y,xs,ys,win) OF plugin IS gl
  281. /************ plugin end ************/
  282.  
  283. -> Magic idenitifier for AppWindow gadgets.
  284. CONST EG_MAGIC=$EA51EA51
  285.  
  286. -> Tag list constants
  287. CONST EG_TAGBASE=TAG_USER+$4000
  288.  
  289. EXPORT ENUM EG_TITLE=EG_TAGBASE, EG_GUI,  EG_INFO, EG_SCRN, EG_FONT, EG_MENU,
  290.             EG_GHVAR, EG_AWPROC, EG_LEFT, EG_TOP,  EG_MAXW, EG_MAXH, EG_WTYPE,
  291.             EG_CLOSE, EG_CLEAN,  EG_HIDE
  292.  
  293. -> Gadget list attribute selection.
  294. #define ATTR(gui,n)        gui[(n)]
  295. #define HasATTR(list,n)    (ListLen((list))>n)
  296. #define OptATTR(list,n)    optattr(list,n)
  297. #define OptDefATTR(list,n) optdefattr(list,n)
  298.  
  299. PROC optattr(list:PTR TO LONG,n) IS IF HasATTR(list,n) THEN ATTR(list,n) ELSE 0
  300.  
  301. PROC optdefattr(list:PTR TO LONG,n)
  302.   DEF res=-1
  303.   IF HasATTR(list,n) THEN res:=ATTR(list,n)
  304. ENDPROC IF res<>-1 THEN res ELSE list
  305.  
  306. PROC indexdata(type)
  307.   DEF index, but=FALSE, val=0
  308.   SELECT MAXGUI OF type
  309.   CASE BUTTON,SBUTTON,RBUTTON;  index:=BUT_DATA; but:=TRUE
  310.   CASE CHECK;    index:=CHK_DATA; val:=CHK_VAL
  311.   CASE LISTV;    index:=LST_DATA
  312.   CASE MX;       index:= MX_DATA
  313.   CASE STR;      index:=STR_DATA; val:=STR_STR
  314.   CASE INTEGER;  index:=INT_DATA; val:=INT_VAL
  315.   CASE CYCLE;    index:=CYC_DATA
  316.   CASE PALETTE;  index:=PAL_DATA
  317.   CASE SCROLL;   index:=SCR_DATA
  318.   CASE SLIDE;    index:=SLI_DATA
  319.   ENDSELECT
  320. ENDPROC index, but, val
  321.  
  322. #ifndef EASY_KEYBOARD
  323. #ifndef EASY_EXTRAS
  324. #define EASY_NOKEYBEXTRA
  325. #endif
  326. #endif
  327.  
  328. #ifndef EASY_NOKEYBEXTRA
  329. -> Optional value based on index.
  330. PROC optindex(i:PTR TO LONG,index) IS IF index THEN OptATTR(i,index) ELSE 0
  331. #endif
  332.  
  333. #ifdef EASY_KEYBOARD
  334. #define optkey(t,i) optindex(i,indexkey(t))
  335. PROC indexkey(type)
  336.   DEF index
  337.   SELECT MAXGUI OF type
  338.   CASE BUTTON,SBUTTON,RBUTTON;  index:=BUT_KEY
  339.   CASE CHECK;    index:=CHK_KEY
  340.   CASE LISTV;    index:=LST_KEY
  341.   CASE MX;       index:= MX_KEY
  342.   CASE STR;      index:=STR_KEY
  343.   CASE INTEGER;  index:=INT_KEY
  344.   CASE CYCLE;    index:=CYC_KEY
  345.   CASE PALETTE;  index:=PAL_KEY
  346.   CASE SCROLL;   index:=SCR_KEY
  347.   CASE SLIDE;    index:=SLI_KEY
  348.   ENDSELECT
  349. ENDPROC index
  350. #endif
  351.  
  352. #ifndef EASY_EXTRAS
  353. #define optdis(t,i) 0
  354. #endif
  355. #ifdef EASY_EXTRAS
  356. #define optdis(t,i) optindex(i,indexdis(t))
  357. PROC indexdis(type)
  358.   DEF index=0
  359.   SELECT MAXGUI OF type
  360.   CASE BUTTON,SBUTTON,RBUTTON;  index:=BUT_DIS
  361.   CASE CHECK;    index:=CHK_DIS
  362.   CASE LISTV;    index:=LST_DIS
  363.   CASE MX;       index:= MX_DIS
  364.   CASE STR;      index:=STR_DIS
  365.   CASE INTEGER;  index:=INT_DIS
  366.   CASE CYCLE;    index:=CYC_DIS
  367.   CASE PALETTE;  index:=PAL_DIS
  368.   CASE SCROLL;   index:=SCR_DIS
  369.   CASE SLIDE;    index:=SLI_DIS
  370.   ENDSELECT
  371. ENDPROC index
  372.  
  373. /********** setdisabled **********/
  374. EXPORT PROC setdisabled(gh,gad:PTR TO LONG,disabled=TRUE)
  375.   DEF index
  376.   index:=indexdis(ATTR(gad,EG_TYPE))
  377.   IF HasATTR(gad,index) THEN setattr(gh,gad,disabled,GA_DISABLED,index)
  378. ENDPROC
  379. #endif
  380.  
  381. -> Clear window contents and redraw frame.
  382. PROC clearwindow(w:PTR TO window)
  383.   fillbox(w.rport,0,w.borderleft,w.bordertop,
  384.           w.width-w.borderright-1, w.height-w.borderbottom-1)
  385.   RefreshWindowFrame(w)
  386. ENDPROC
  387.  
  388. PROC fillbox(rport,pen,x,y,x2,y2)
  389.   SetAPen(rport,pen)
  390.   RectFill(rport,x,y,x2,y2)
  391. ENDPROC
  392.  
  393. -> Create new gadget data.
  394. PROC newg(xs,ys,type,list,flags=0,mid=NO_MID) IS NEW [0,0,0,xs,ys,type,list,flags,mid]:g
  395.  
  396. -> Access functions for gadget type mapping lists.
  397. PROC minARGS() IS MINARGS
  398. PROC kindTAB() IS KINDTAB
  399.  
  400. #ifdef EASYGUI_DEBUG
  401. -> In debug version this will be called instead of raising an exception.
  402. PROC myraise(x,l,s)
  403.   exception:=x;  exceptioninfo:=0
  404.   WriteF('Just about to raise exception:\n')
  405.   report_exception()
  406.   IF (l>0) AND (l<2000)
  407.     WriteF(' Error ref \d: \s\n',l,s)
  408.   ELSE
  409.     WriteF(' \s (Gadget list $\h)\n',s,l)
  410.   ENDIF
  411.   Raise(x)
  412. ENDPROC
  413. #endif
  414.  
  415. /********** easyguiA() **********/
  416. EXPORT PROC easyguiA(title,gui,tags=NIL) HANDLE
  417.   DEF gh=NIL:PTR TO guihandle,res=-1
  418.   gh:=guiinitA(title,gui,tags)
  419.   WHILE res<0
  420.     Wait(gh.sig)
  421.     res:=guimessage(gh)
  422.   ENDWHILE
  423. EXCEPT DO
  424.   cleangui(gh)
  425.   ReThrow()
  426. ENDPROC res
  427.  
  428. /********** easygui_fallbackA() **********/
  429. EXPORT PROC easygui_fallbackA(title,gui,tags=NIL) HANDLE
  430.   RETURN easyguiA(title,gui,tags)
  431. EXCEPT
  432.   IF exception="bigg"
  433.     RETURN easyguiA(title,gui,[EG_FONT,['topaz.font',8,0,0]:textattr,
  434.                                TAG_MORE,tags])
  435.   ENDIF
  436.   ReThrow()
  437. ENDPROC
  438.  
  439. -> Init font.
  440. PROC initfont(gh:PTR TO guihandle,tattr)
  441.   gh.tattr:=tattr
  442.   gh.ta_scr:=(tattr=NIL)
  443. ENDPROC
  444.  
  445. -> Init screen.
  446. PROC initscr(gh:PTR TO guihandle,scr)
  447.   gh.scr:=scr
  448.   gh.is_wb:=(scr=NIL)
  449. ENDPROC
  450.  
  451. -> Set up menus.
  452. PROC setmenus(gh:PTR TO guihandle)
  453.   -> setup menus
  454.   IF gh.newmenus
  455.     gh.menus:=CreateMenusA(gh.newmenus,NIL)
  456.     IF gh.menus=NIL THEN RaiseX("GUI",431,'Could not create menus. Bad menu description? Or out of memory?')
  457.     IF LayoutMenusA(gh.menus,gh.visual,[GTMN_NEWLOOKMENUS,TRUE,NIL])=FALSE THEN RaiseX("GUI",432,'Could not layout menus. Out of memory?')
  458.     IF SetMenuStrip(gh.pwnd,gh.menus)=FALSE THEN RaiseX("GUI",433,'Could not set menu strip. Should never happen!')
  459.   ENDIF
  460. ENDPROC
  461.  
  462. PROC win_off(n,s:PTR TO screen)
  463.   DEF y
  464.   IF n=WTYPE_NOBORDER THEN RETURN 1,1
  465.   y:=s.wbortop+TOPSPACE
  466.   IF n>WTYPE_BASIC THEN y:=y+s.rastport.txheight+1
  467. ENDPROC s.wborleft+SIDESPACE,y
  468.  
  469. PROC win_pad(n,s:PTR TO screen)
  470.   DEF y=TOPSPACE
  471.   IF n=WTYPE_NOBORDER THEN RETURN 1,1
  472.   y:=y+IF n=WTYPE_SIZE THEN getrealbot(s) ELSE s.wborbottom
  473. ENDPROC s.wborright+SIDESPACE,y
  474.  
  475. -> Set up GUI.
  476. PROC setgui(gh:PTR TO guihandle)
  477.   DEF base:PTR TO g,s:PTR TO screen,w:PTR TO window,xsize,ysize,
  478.       cm,h=NIL:PTR TO LONG,vpe=NIL:PTR TO viewportextra,x,y
  479.   s:=gh.scr
  480.   w:=gh.pwnd
  481.  
  482.   -> Get gadget data and calculate minimum GUI size.
  483.   gh.base:=base:=minsize(gh.gui,gh)
  484.   IF w=NIL
  485.     -> Calculate offset of borders in window.
  486.     x,y:=win_off(gh.wtype,s)
  487.     gh.xoff:=x
  488.     gh.yoff:=y
  489.   ENDIF
  490.   -> Calculate minimum width and height of window.
  491.   x,y:=win_pad(gh.wtype,s)
  492.   xsize:=x+gh.xoff+base.xs
  493.   ysize:=y+gh.yoff+base.ys
  494.  
  495.   IF (xsize>s.width) OR (ysize>s.height) THEN RaiseX("bigg",455,'Size is too big for the screen.')
  496.  
  497. #ifdef EASY_EXTRAS
  498.   -> If window open then adjust sizing.
  499.   IF w
  500.     -> Calculate X size and pos delta if needed.
  501.     cm:=IF (w.width>=xsize) AND DoesXResize(base.flags) THEN w.width ELSE xsize
  502.     x:=IF cm+w.leftedge>s.width THEN s.width-cm ELSE w.leftedge
  503.     -> Calculate Y size and pos delta if needed.
  504.     h:=IF (w.height>=ysize) AND DoesYResize(base.flags) THEN w.height ELSE ysize
  505.     y:=IF h+w.topedge>s.height THEN s.height-h ELSE w.topedge
  506.     -> Disallow window sizing.
  507.     ModifyIDCMP(w, WIN_IDCMP_NS)
  508.     -> Temporarily allow window to grow as large and small as possible.
  509.     WindowLimits(w,8,8,-1,-1)
  510.     -> Move and size window.
  511.     ChangeWindowBox(w,x,y,cm,h)
  512.     -> Set window to proper limits.
  513.     setwinlimits(w,xsize,ysize,
  514.                    IF DoesXResize(base.flags) THEN -1 ELSE xsize,
  515.                    IF DoesYResize(base.flags) THEN -1 ELSE ysize)
  516.     -> Remove mess.
  517.     clearwindow(w)
  518.     -> Allow resizing (maybe) again.
  519.     ModifyIDCMP(w, WIN_IDCMP)
  520.   ELSE
  521. #endif
  522.   -> Window not open so create it.
  523.     -> get visual infos
  524.     gh.visual:=GetVisualInfoA(gh.scr,NIL)
  525.     IF gh.visual=NIL THEN RaiseX("GUI",482,'Could not get visual info. Out of memory?')
  526.  
  527.     -> calc window position (centre of visible part of screen)
  528.     h:=VTAG_VIEWPORTEXTRA_GET  -> Ack! VideoControl changes tag!
  529.     IF IF cm:=s.viewport.colormap THEN VideoControl(cm, h:=[h,NIL,NIL]) BUT vpe:=h[1] ELSE vpe:=NIL
  530.       x:=Min(vpe.displayclip.maxx-vpe.displayclip.minx+1,s.width)-xsize/2-s.viewport.dxoffset
  531.       y:=Min(vpe.displayclip.maxy-vpe.displayclip.miny+1,s.height)-ysize/2-s.viewport.dyoffset
  532.     ELSE
  533.       x:=s.width-xsize/2
  534.       y:=s.height-ysize/2
  535.     ENDIF
  536.     w:=s.width
  537.     h:=s.height
  538.     -> If position stored use that, else centred.  And adjust max size.
  539.     IF gh.x<>-1
  540.       x:=gh.x
  541.       -> Offset the maximum
  542.       w:=Bounds(w-x,xsize,w)
  543.     ENDIF
  544.     IF gh.y<>-1
  545.       y:=gh.y
  546.       h:=Bounds(h-y,ysize,h)
  547.     ENDIF
  548.     -> Use minimum or stored size (default is maximum).
  549.     IF gh.xsize=0
  550.       w:=xsize
  551.     ELSEIF DoesXResize(base.flags)=FALSE
  552.       w:=xsize
  553.     ELSEIF gh.xsize<>-1
  554.       w:=Bounds(gh.xsize,xsize,s.width)
  555.     ENDIF
  556.     IF gh.ysize=0
  557.       h:=ysize
  558.     ELSEIF DoesYResize(base.flags)=FALSE
  559.       h:=ysize
  560.     ELSEIF gh.ysize<>-1
  561.       h:=Bounds(gh.ysize,ysize,s.height)
  562.     ENDIF
  563.  
  564.     -> open the window
  565.     gh.pwnd:=w:=OpenWindowTagList(NIL,
  566.                [WA_LEFT,       Bounds(x,0,s.width-w),
  567.                 WA_TOP,        Bounds(y,0,s.height-h),
  568.                 WA_WIDTH,      w,
  569.                 WA_HEIGHT,     h,
  570.                 WA_IDCMP,      0, -> Was WIN_IDCMP: now ports are shared.
  571.                 WA_FLAGS,      ListItem([WIN_FNOBORD,WIN_FBASIC,
  572.                                          WIN_FNOSIZE,WIN_FSIZE], gh.wtype),
  573.                 WA_TITLE,      IF gh.wtype>WTYPE_BASIC THEN gh.wtitle ELSE NIL,
  574.                 WA_CUSTOMSCREEN, gh.scr,
  575.                 WA_MINWIDTH,   xsize,
  576.                 WA_MINHEIGHT,  ysize,
  577.                 WA_MAXWIDTH,   IF DoesXResize(base.flags) THEN -1 ELSE xsize,
  578.                 WA_MAXHEIGHT,  IF DoesYResize(base.flags) THEN -1 ELSE ysize,
  579.                 ->WA_AUTOADJUST,1,
  580.                 NIL])
  581.     IF w=NIL THEN RaiseX("GUI",537,'Could not open window. Too many layers?')
  582.     w.userdata:=gh
  583.     -> Set up window IDCMP port.
  584.     w.userport:=gh.wndport
  585.     ModifyIDCMP(w,WIN_IDCMP)
  586.  
  587. #ifdef EASY_APPWINDOW
  588.     IF gh.awproc THEN gh.appwin:=AddAppWindowA(gh,gh.awproc,gh.pwnd,gh.awport,NIL)
  589. #endif
  590.     stdrast:=w.rport
  591. #ifdef EASY_EXTRAS
  592.   ENDIF
  593. #endif
  594.   -> Remember minimum window size.
  595.   gh.xsize:=xsize
  596.   gh.ysize:=ysize
  597.   -> Now render the gadgets.
  598.   gh.glist:=rendergui(gh)
  599. ENDPROC
  600.  
  601. /********** guiinitA() **********/
  602. #ifdef EASY_EXTRAS
  603. EXPORT PROC guiinitA(title,gui,tags=NIL) IS addmultiA(NIL,title,gui,tags)
  604. #endif
  605. #ifndef EASY_EXTRAS
  606. EXPORT PROC guiinitA(title,gui,tags=NIL) HANDLE
  607.   DEF gh=NIL:PTR TO guihandle
  608.   gh:=makehandle(title,gui,NIL,tags)
  609. EXCEPT
  610.   -> Stop the user cleanup in this case.
  611.   gh.onclean:=NIL
  612.   cleangui(gh)
  613.   ReThrow()
  614. ENDPROC gh
  615. #endif
  616.  
  617. PROC openlibrary(s)
  618.   DEF lib
  619.   IF (lib:=OpenLibrary(s,37))=NIL THEN RaiseX("LIB",613,s)
  620. ENDPROC lib
  621.  
  622. -> Make a handle and initialise from the tags.
  623. PROC makehandle(title,gui,mh,tags) HANDLE
  624.   DEF gh=NIL:PTR TO guihandle, temp:PTR TO LONG, isopen=FALSE
  625.   NEW gh
  626.   utilitybase:=openlibrary('utility.library')
  627.   isopen:=TRUE
  628.   IF temp:=GetTagData(EG_GHVAR,NIL,tags) THEN temp[]:=gh
  629.   gh.wtype:=GetTagData(EG_WTYPE,WTYPE_SIZE,tags)
  630.   gh.wtitle:=title
  631.   gh.gui:=gui
  632.   gh.info:=IF -1<>(temp:=GetTagData(EG_INFO,-1,tags)) THEN temp ELSE gh
  633.   initscr(gh,GetTagData(EG_SCRN,NIL,tags))
  634.   initfont(gh,GetTagData(EG_FONT,NIL,tags))
  635.   gh.newmenus:=GetTagData(EG_MENU,NIL,tags)
  636.   gh.awproc:=GetTagData(EG_AWPROC,NIL,tags)
  637.   gh.x:=GetTagData(EG_LEFT,-1,tags)
  638.   gh.y:=GetTagData(EG_TOP,-1,tags)
  639.   gh.onclose:=GetTagData(EG_CLOSE,NIL,tags)
  640.   gh.onclean:=GetTagData(EG_CLEAN,NIL,tags)
  641.   IF GetTagData(EG_MAXW,FALSE,tags) THEN gh.xsize:=-1
  642.   IF GetTagData(EG_MAXH,FALSE,tags) THEN gh.ysize:=-1
  643. #ifdef EASY_EXTRAS
  644.   gh.mh:=mh
  645. #endif
  646.   setinit(gh)
  647. EXCEPT DO
  648.   IF exception
  649.     END gh
  650.     ReThrow()
  651.   ELSE
  652.     IF GetTagData(EG_HIDE,FALSE,tags)=FALSE THEN openwin(gh)
  653.   ENDIF
  654.   IF isopen THEN CloseLibrary(utilitybase)
  655. ENDPROC gh
  656.  
  657. -> Initialisation stuff.
  658. PROC setinit(gh:PTR TO guihandle) HANDLE
  659.   -> Open library safely.
  660.   gadtoolsbase:=openlibrary('gadtools.library')
  661.   gh.gt_isopen:=TRUE
  662. #ifdef EASY_EXTRAS
  663.   -> Window IDCMP port.
  664.   IF gh.mh
  665.     -> If multi-window then share port.
  666.     gh.wndport:=gh.mh.wndport
  667.     -> Also, share the *complete* signal mask.
  668.     -> (This ensures that guimessage() works...)
  669.     gh.sig:=gh.mh.sig
  670.   ELSE
  671. #endif
  672.     gh.wndport:=makeport()
  673.     gh.sig:=Shl(1,gh.wndport.sigbit)
  674. #ifdef EASY_EXTRAS
  675.   ENDIF
  676. #endif
  677. #ifdef EASY_APPWINDOW
  678.   -> Open library safely.
  679.   workbenchbase:=openlibrary('workbench.library')
  680.   gh.wb_isopen:=TRUE
  681. #ifdef EASY_EXTRAS
  682.   -> AppWindow port
  683.   IF gh.mh
  684.     -> If multi-window then share port (even if no awproc)
  685.     -> (This ensures that guimessage() works...)
  686.     gh.awport:=gh.mh.awport
  687.   ELSEIF gh.awproc
  688. #endif
  689. #ifndef EASY_EXTRAS
  690.   IF gh.awproc
  691. #endif
  692.     gh.awport:=makeport()
  693.     gh.sig:=gh.sig OR Shl(1,gh.awport.sigbit)
  694.   ELSE
  695.     gh.awport:=NIL
  696.   ENDIF
  697. #endif
  698. EXCEPT
  699.   cleaninit(gh)
  700.   ReThrow()
  701. ENDPROC
  702.  
  703. /********** openwin() **********/
  704. EXPORT PROC openwin(gh:PTR TO guihandle)
  705.   IF gh.pwnd=NIL
  706.     -> Set up screen.
  707.     IF gh.is_wb
  708.       IF gh.scr=NIL THEN gh.scr:=LockPubScreen(NIL)
  709.       IF gh.scr=NIL THEN RaiseX("GUI",417,'Could not lock default public screen (Workbench?). Is it open?')
  710.     ENDIF
  711.     -> Set up font.
  712.     IF gh.ta_scr THEN gh.tattr:=gh.scr.font
  713.     -> Set up window and GUI.
  714.     setgui(gh)
  715.     -> Set up menus.
  716.     setmenus(gh)
  717. #ifdef EASY_EXTRAS
  718.     -> If multi then bump count of open windows.
  719.     IF gh.mh THEN gh.mh.opencount:=gh.mh.opencount+1
  720. #endif
  721.   ENDIF
  722. ENDPROC gh
  723.  
  724. #ifdef EASY_EXTRAS
  725. /********** changescreen() **********/
  726. EXPORT PROC changescreen(gh:PTR TO guihandle,scr=NIL)
  727.   IF gh.wnd=NIL THEN initscr(gh,scr)
  728. ENDPROC
  729.  
  730. /********** changefont() **********/
  731. EXPORT PROC changefont(gh:PTR TO guihandle,tattr=NIL)
  732.   IF gh.wnd=NIL THEN initfont(gh,tattr)
  733. ENDPROC
  734.  
  735. /********** changewintype() **********/
  736. EXPORT PROC changewintype(gh:PTR TO guihandle,wintype=WTYPE_SIZE)
  737.   IF gh.wnd=NIL THEN gh.wtype:=wintype
  738. ENDPROC
  739.  
  740. /********** changeinfo() **********/
  741. EXPORT PROC changeinfo(gh:PTR TO guihandle,info=-1)
  742.   gh.info:=IF info<>-1 THEN info ELSE gh
  743. ENDPROC
  744.  
  745. /********** changetitle() **********/
  746. EXPORT PROC changetitle(gh:PTR TO guihandle,windowtitle=NIL)
  747.   IF gh.wnd
  748.     IF (windowtitle=NIL) OR (gh.wtype>WTYPE_BASIC)
  749.       SetWindowTitles(gh.wnd, windowtitle, -1)
  750.     ENDIF
  751.   ENDIF
  752.   gh.wtitle:=windowtitle
  753. ENDPROC
  754.  
  755. /********** changemenus() **********/
  756. EXPORT PROC changemenus(gh:PTR TO guihandle,newmenus=NIL) HANDLE
  757.   IF gh.wnd THEN removemenus(gh)
  758.   gh.newmenus:=newmenus
  759.   IF gh.wnd THEN setmenus(gh)
  760. EXCEPT
  761.   removemenus(gh)
  762.   ReThrow()
  763. ENDPROC
  764.  
  765. /********** changegui() **********/
  766. EXPORT PROC changegui(gh:PTR TO guihandle,gui)
  767.   IF gui
  768.     IF gh.pwnd THEN removegui(gh)
  769.     gh.gui:=gui
  770.     IF gh.pwnd THEN setgui(gh)
  771.   ENDIF
  772. ENDPROC
  773.  
  774. /********** movewin() **********/
  775. EXPORT PROC movewin(gh:PTR TO guihandle,x=-1,y=-1)
  776.   DEF w:PTR TO window
  777.   IF w:=gh.wnd
  778.     MoveWindow(w, IF x=-1 THEN 0 ELSE (x-w.leftedge),
  779.                   IF y=-1 THEN 0 ELSE (y-w.topedge))
  780.   ENDIF
  781. ENDPROC
  782.  
  783. /********** sizewin() **********/
  784. EXPORT PROC sizewin(gh:PTR TO guihandle,xs=-1,ys=-1)
  785.   DEF w:PTR TO window
  786.   IF w:=gh.wnd
  787.     SizeWindow(w, IF xs=-1 THEN 0 ELSE (xs-w.width),
  788.                   IF ys=-1 THEN 0 ELSE (ys-w.height))
  789.   ENDIF
  790. ENDPROC
  791.  
  792. -> Try setting window limits a few times.
  793. PROC setwinlimits(w,minx,miny,maxx,maxy)
  794.   DEF i
  795.   FOR i:=0 TO 3
  796.   EXIT WindowLimits(w,minx,miny,maxx,maxy)
  797.     Delay(1)
  798.   ENDFOR
  799. ENDPROC
  800.  
  801. /********** blockwin() **********/
  802. EXPORT PROC blockwin(gh:PTR TO guihandle)
  803.   DEF lib:PTR TO lib,c,w:PTR TO window
  804.   gh.blockcnt:=(c:=gh.blockcnt)+1
  805.   IF c=0
  806.     -> Only works if window open and not already blocked.
  807.     IF (w:=gh.wnd) AND (gh.req=NIL)
  808.       -> Only allow window refresh messages.
  809.       ModifyIDCMP(w, IDCMP_REFRESHWINDOW)
  810.       -> Stop window sizing.
  811.       setwinlimits(w,w.width,w.height,w.width,w.height)
  812.       NEW gh.req
  813.       -> Block window with requester.
  814.       InitRequester(gh.req)
  815.       Request(gh.req, w)
  816.       lib:=intuitionbase
  817.       IF lib.version>=39 THEN SetWindowPointerA(w,[WA_BUSYPOINTER,TRUE,
  818.                                                    WA_POINTERDELAY,TRUE,NIL])
  819.     ENDIF
  820.   ENDIF
  821. ENDPROC
  822.  
  823. /********** unblockwin() **********/
  824. EXPORT PROC unblockwin(gh:PTR TO guihandle)
  825.   DEF lib:PTR TO lib,c,w:PTR TO window
  826.   IF (c:=gh.blockcnt)>0
  827.     gh.blockcnt:=c-1
  828.     IF c=1
  829.       -> Only works if window open and blocked.
  830.       IF (w:=gh.wnd) AND (gh.req<>NIL)
  831.         -> Remove requester.
  832.         EndRequest(gh.req, w)
  833.         -> Reset window limits.
  834.         setwinlimits(w,gh.xsize,gh.ysize,
  835.                        IF DoesXResize(gh.base.flags) THEN -1 ELSE gh.xsize,
  836.                        IF DoesYResize(gh.base.flags) THEN -1 ELSE gh.ysize)
  837.         -> Reset IDCMP.
  838.         ModifyIDCMP(w, WIN_IDCMP)
  839.         END gh.req
  840.         lib:=intuitionbase
  841.         IF lib.version>=39 THEN SetWindowPointerA(w,[WA_BUSYPOINTER,FALSE,NIL])
  842.       ENDIF
  843.     ENDIF
  844.   ENDIF
  845. ENDPROC
  846. #endif
  847.  
  848. #ifdef EASY_APPWINDOW
  849. -> Handle AppWindow messages.
  850. PROC appwmessage(port) HANDLE
  851.   DEF ret,data,list:PTR TO LONG,amsg=NIL:PTR TO appmessage,gh:PTR TO guihandle,
  852.       pl:PTR TO plugin
  853.   IF port
  854.     WHILE amsg:=GetMsg(port)
  855.       -> Get guihandle from message ID.
  856.       gh:=amsg.id
  857.       -> See if any PLUGIN wants it.
  858.       pl:=gh.plugins
  859.       WHILE pl
  860.         IF OptATTR(pl.base.list,PLG_APPW)=NIL THEN JUMP plugin_appw_skip
  861.       EXIT pl.appmessage(amsg,gh.pwnd)
  862. plugin_appw_skip:
  863.         pl:=pl.next
  864.       ENDWHILE
  865.       ret:=NIL
  866.       data:=NIL
  867.       -> Get awproc (in ret) and data.
  868.       IF pl
  869.         ret:=OptATTR(pl.base.list,PLG_APPW)
  870.         data:=pl
  871.       ELSE
  872.         IF list:=findxy(gh,amsg.mousex,amsg.mousey)
  873.           SELECT MAXGUI OF ATTR(list,EG_TYPE)
  874.           CASE BUTTON, SBUTTON, RBUTTON
  875.             ret:=OptATTR(list,BUT_APPW)
  876.             data:=OptDefATTR(list,BUT_DATA)
  877.           CASE LISTV
  878.             ret:=OptATTR(list,LST_APPW)
  879.             data:=OptDefATTR(list,LST_DATA)
  880.           CASE STR
  881.             ret:=OptATTR(list,STR_APPW)
  882.             data:=OptDefATTR(list,STR_DATA)
  883.           ENDSELECT
  884.         ENDIF
  885.       ENDIF
  886.       -> If no gadget awproc then use window one.
  887.       IF ret=NIL
  888.         ret:=amsg.userdata
  889.         data:=NIL
  890.       ENDIF
  891.       -> Call the awproc.
  892.       IF ret THEN ret(data,gh.info,amsg)
  893.       -> Now we can reply to the message.
  894.       ReplyMsg(amsg)
  895.       amsg:=NIL
  896.     ENDWHILE
  897.   ENDIF
  898. EXCEPT
  899.   -> Still need to reply if exception happened at a bad point
  900.   IF amsg THEN ReplyMsg(amsg)
  901.   ReThrow()
  902. ENDPROC
  903. #endif
  904.  
  905. -> Handle menu messages.
  906. PROC menumessage(gh:PTR TO guihandle,code) HANDLE
  907.   DEF ret=GUI_CONT,menunum,item:PTR TO menuitem
  908.   menunum:=Unsigned(code)
  909.   -> Stop if the window's gone away.
  910.   WHILE (menunum<>MENUNULL) AND gh.pwnd
  911.     item:=ItemAddress(gh.menus,menunum)
  912.     -> Get action value/function.
  913.     ret:=GTMENUITEM_USERDATA(item)
  914.   -> Stop if action value.
  915.   EXIT IsActionFun(ret)=FALSE
  916.     gh.menuitem:={item}
  917.     -> Call action function.
  918.     ret(NIL,NIL,gh.info)
  919.     ret:=GUI_CONT
  920.   EXIT item=NIL
  921.     menunum:=Unsigned(item.nextselect)
  922.   ENDWHILE
  923. EXCEPT DO
  924.   gh.menuitem:=NIL
  925.   ReThrow()
  926. ENDPROC ret
  927.  
  928. -> Handle GadTools/window messages.
  929. PROC gtmessage(port) HANDLE
  930.   DEF ret=GUI_CONT,mes=NIL:PTR TO intuimessage,type,gh:PTR TO guihandle,
  931.       gs:PTR TO gadget,list:PTR TO LONG,code,pl:PTR TO plugin,qual
  932.   WHILE mes:=Gt_GetIMsg(port)
  933.     -> Get guihandle from window userdata.
  934.     gh:=mes.idcmpwindow.userdata
  935.     -> See if any PLUGIN wants it.
  936.     pl:=gh.plugins
  937.     WHILE pl
  938.     EXIT pl.message_test(mes,gh.pwnd)
  939.       pl:=pl.next
  940.     ENDWHILE
  941.     -> Copy important bits of the message.
  942.     type:=mes.class
  943.     code:=mes.code
  944.     gs:=mes.iaddress
  945.     qual:=Unsigned(mes.qualifier)
  946.     -> Now we can reply to the message.
  947.     Gt_ReplyIMsg(mes)
  948.     mes:=NIL
  949.     IF pl
  950.       -> Call the PLUGIN's action function if necessary.
  951.       IF pl.message_action(type,qual,code,gh.pwnd)
  952.         ret:=ATTR(pl.base.list,PLG_ACT)
  953.         IF IsActionFun(ret)
  954.           ret(gh.info,pl)
  955.           ret:=GUI_CONT
  956.         ENDIF
  957.       ENDIF
  958.     ELSE
  959.       -> Gadget click.
  960.       IF type AND GAD_IDCMP
  961. ->WriteF('type=$\h, code=$\h, gad=$\h\n', type, code, gs)
  962.         -> Protect from stray IDCMP_MOUSEMOVE.
  963.         IF gs AND (gs<>gh.pwnd)
  964.           -> Get gadget description list.
  965.           list:=gs.userdata
  966.           -> Set new attribute.
  967.           performset(gs,code,list)
  968.           -> Get action value/function.
  969.           ret:=ATTR(list,EG_ACT)
  970.           IF IsActionFun(ret)
  971.             performaction(ret,gs,gh.info,code,list,qual)
  972.             ret:=GUI_CONT
  973.           ENDIF
  974.         ENDIF
  975. #ifdef EASY_KEYBOARD
  976.       -> Key press.
  977.       ELSEIF type=IDCMP_VANILLAKEY
  978.         ret:=performkey(gh,code)
  979. #endif
  980.       -> Window refresh.
  981.       ELSEIF type=IDCMP_REFRESHWINDOW
  982.         Gt_BeginRefresh(gh.pwnd)
  983.         Gt_EndRefresh(gh.pwnd,TRUE)
  984.       -> Window size change.
  985.       ELSEIF type=IDCMP_NEWSIZE
  986.         -> Remove the gadgets, clear and recreate.
  987.         removegads(gh)
  988.         clearwindow(gh.pwnd)
  989.         gh.glist:=rendergui(gh)
  990.       -> Close gadget click.
  991.       ELSEIF type=IDCMP_CLOSEWINDOW
  992.         -> Find action value/function.
  993.         ret:=gh.onclose
  994.         IF IsActionFun(ret)
  995. #ifdef EASY_EXTRAS
  996.           ret(gh.mh,gh.info)
  997. #endif
  998. #ifndef EASY_EXTRAS
  999.           ret(NIL,gh.info)
  1000. #endif
  1001.           ret:=GUI_CONT
  1002.         ENDIF
  1003.       -> Menu choice(s).
  1004.       ELSEIF type=IDCMP_MENUPICK
  1005.         ret:=menumessage(gh,code)
  1006.       ENDIF
  1007.     ENDIF
  1008.   EXIT ret<>GUI_CONT
  1009.   ENDWHILE
  1010. #ifdef EASY_EXTRAS
  1011.   IF ret<>GUI_CONT THEN IF gh.mh THEN cleangui(gh)
  1012. #endif
  1013. EXCEPT
  1014.   -> Still need to reply if exception happened in PLUGIN message_test().
  1015.   IF mes THEN Gt_ReplyIMsg(mes)
  1016.   ReThrow()
  1017. ENDPROC ret
  1018.  
  1019. #ifdef EASY_EXTRAS
  1020. /********** multiinit() **********/
  1021. EXPORT PROC multiinit() HANDLE
  1022.   DEF mh=NIL:PTR TO multihandle
  1023.   NEW mh
  1024.   newList(mh.guis)
  1025.   mh.wndport:=makeport()
  1026.   mh.sig:=Shl(1,mh.wndport.sigbit)
  1027. #ifdef EASY_APPWINDOW
  1028.   mh.awport:=makeport()
  1029.   mh.sig:=mh.sig OR Shl(1,mh.awport.sigbit)
  1030. #endif
  1031. EXCEPT
  1032.   cleanmulti(mh)
  1033.   ReThrow()
  1034. ENDPROC mh
  1035.  
  1036. /********** addmultiA() **********/
  1037. EXPORT PROC addmultiA(mh:PTR TO multihandle,title,gui,tags=NIL) HANDLE
  1038.   DEF gh=NIL:PTR TO guihandle
  1039.   gh:=makehandle(title,gui,mh,tags)
  1040.   IF mh THEN AddHead(mh.guis,gh.link)
  1041. EXCEPT
  1042.   -> Stop the user cleanup in this case.
  1043.   gh.onclean:=NIL
  1044.   cleangui(gh)
  1045.   ReThrow()
  1046. ENDPROC gh
  1047.  
  1048. /********** multiforall() **********/
  1049. EXPORT PROC multiforall(varaddr:PTR TO LONG,mh:PTR TO multihandle,expr) IS
  1050.   multieval(varaddr,mh,expr,FALSE)
  1051.  
  1052. /********** multiexists() **********/
  1053. EXPORT PROC multiexists(varaddr:PTR TO LONG,mh:PTR TO multihandle,expr) IS
  1054.   multieval(varaddr,mh,expr,TRUE)
  1055.  
  1056. -> Evaluate and maybe stop...
  1057. PROC multieval(varaddr:PTR TO LONG,mh:PTR TO multihandle,expr,exists)
  1058.   DEF node:PTR TO ln, next, this, res
  1059.   -> If empty then TRUE for forall, but FALSE for exists
  1060.   res:=(exists=FALSE)
  1061.   IF mh
  1062.     node:=mh.guis.head
  1063.     WHILE next:=node.succ
  1064.       varaddr[]:=node-GH_LINK_OFFSET
  1065.       IF this:=Eval(expr)
  1066.         -> If exists then we've found a match.
  1067.         IF exists THEN RETURN this
  1068.       ELSE
  1069.         -> Forall is FALSE.  Exists is still FALSE.
  1070.         res:=FALSE
  1071.       ENDIF
  1072.       node:=next
  1073.     ENDWHILE
  1074.   ENDIF
  1075.   -> Invalidate for case where exists fails.
  1076.   varaddr[]:=NIL
  1077. ENDPROC res
  1078.  
  1079. /********** multiempty() **********/
  1080. EXPORT PROC multiempty(mh:PTR TO multihandle) IS mh.guis.tailpred=mh.guis
  1081.  
  1082. /********** multiloop() **********/
  1083. EXPORT PROC multiloop(mh:PTR TO multihandle)
  1084.   DEF res=-1
  1085.   WHILE res<0
  1086.   EXIT mh.opencount=0
  1087.     Wait(mh.sig)
  1088.     res:=multimessage(mh)
  1089.   ENDWHILE
  1090. ENDPROC res
  1091.  
  1092. /********** cleanmulti() **********/
  1093. EXPORT PROC cleanmulti(mh:PTR TO multihandle)
  1094.   IF mh
  1095.     -> Clean up any remaining guihandles.
  1096.     WHILE multiempty(mh)=FALSE DO cleangui(mh.guis.head-GH_LINK_OFFSET)
  1097. #ifdef EASY_APPWINDOW
  1098.     IF mh.awport
  1099.       DeleteMsgPort(mh.awport)
  1100.       mh.awport:=NIL
  1101.     ENDIF
  1102. #endif    
  1103.     IF mh.wndport
  1104.       DeleteMsgPort(mh.wndport)
  1105.       mh.wndport:=NIL
  1106.     ENDIF
  1107.     END mh
  1108.   ENDIF
  1109. ENDPROC
  1110.  
  1111. /********** checkmulti() **********/
  1112. EXPORT PROC checkmulti(mh:PTR TO multihandle)
  1113.   DEF ret
  1114.   -> Check if there a message waiting on our ports.
  1115.   IF SetSignal(0,0) AND mh.sig
  1116.     IF (ret:=multimessage(mh))>=0 THEN quitgui(ret)
  1117.   ENDIF
  1118. ENDPROC
  1119. #endif
  1120.  
  1121. -> Note: as long as gh is valid, guimessage() can be used in place of
  1122. -> multimessage() for multi-window GUIs.  But remember that gh could
  1123. -> be invalidated by an action function when guimessage() is called.
  1124.  
  1125. /********** guimessage() **********/
  1126. /********** multimessage() **********/
  1127. #ifdef EASY_APPWINDOW
  1128. EXPORT PROC guimessage(gh:PTR TO guihandle)     IS message(gh.wndport,gh.awport)
  1129. #ifdef EASY_EXTRAS
  1130. EXPORT PROC multimessage(mh:PTR TO multihandle) IS message(mh.wndport,mh.awport)
  1131. #endif
  1132. #endif
  1133. #ifndef EASY_APPWINDOW
  1134. EXPORT PROC guimessage(gh:PTR TO guihandle)     IS message(gh.wndport,NIL)
  1135. #ifdef EASY_EXTRAS
  1136. EXPORT PROC multimessage(mh:PTR TO multihandle) IS message(mh.wndport,NIL)
  1137. #endif
  1138. #endif
  1139.  
  1140. -> Handle messages from the ports.
  1141. PROC message(wndport,awport) HANDLE
  1142.   DEF ret=-1
  1143. #ifdef EASY_APPWINDOW
  1144.   appwmessage(awport)
  1145. #endif
  1146.   ret:=gtmessage(wndport)
  1147. EXCEPT
  1148.   -> If we got "QUIT" then return value is in exceptioninfo.
  1149.   IF exception="QUIT"
  1150.     ret:=exceptioninfo
  1151.   ELSE
  1152.     ReThrow()
  1153.   ENDIF
  1154. ENDPROC ret
  1155.  
  1156. /********** quitgui() **********/
  1157. EXPORT PROC quitgui(ret=0) IS Throw("QUIT",ret)
  1158.  
  1159. -> Note: as above, checkgui() is safe for multi-window GUIs as long as
  1160. -> gh is valid.
  1161.  
  1162. /********** checkgui() **********/
  1163. EXPORT PROC checkgui(gh:PTR TO guihandle)
  1164.   DEF ret
  1165.   -> Check if there a message waiting on our ports.
  1166.   IF SetSignal(0,0) AND gh.sig
  1167.     IF (ret:=guimessage(gh))>=0 THEN quitgui(ret)
  1168.   ENDIF
  1169. ENDPROC
  1170.  
  1171. -> Remove menus and reset handle.
  1172. PROC removemenus(gh:PTR TO guihandle)
  1173.   IF gh.menus
  1174.     -> Hack to prevent the item.nextselect if closed from menu action function.
  1175.     IF gh.menuitem THEN gh.menuitem[]:=NIL
  1176.     IF gh.pwnd THEN ClearMenuStrip(gh.pwnd)
  1177.     FreeMenus(gh.menus)
  1178.     gh.menus:=NIL
  1179.   ENDIF
  1180. ENDPROC
  1181.  
  1182. -> Remove GUI and reset handle.
  1183. PROC removegui(gh:PTR TO guihandle)
  1184.   clean(gh.base)
  1185.   gh.base:=NIL
  1186.   removegads(gh)
  1187.   gh.glist:=NIL
  1188.   gh.plugins:=NIL
  1189. ENDPROC
  1190.  
  1191. -> Check if is this an IDCMP message for the window.
  1192. PROC testintuimsg(msg:PTR TO intuimessage,data) IS msg.idcmpwindow=data
  1193.  
  1194. #ifdef EASY_APPWINDOW
  1195. -> Check if is this an appmessage for the AppWindow.
  1196. PROC testappwmsg(msg:PTR TO appmessage,data) IS msg.id=data
  1197. #endif
  1198.  
  1199. -> Selectively remove messages from the port.
  1200. PROC clearmsgs(mp:PTR TO mp,f,data)
  1201.   DEF msg:PTR TO mn, succ
  1202.   -> Must be in Forbid()/Permit() brackets...
  1203.   Forbid()
  1204.   msg:=mp.msglist.head
  1205.   WHILE succ:=msg.ln.succ
  1206.     IF f(msg,data)
  1207.       Remove(msg)
  1208.       ReplyMsg(msg)
  1209.     ENDIF
  1210.     msg:=succ
  1211.   ENDWHILE
  1212.   Permit()
  1213. ENDPROC
  1214.  
  1215. -> Create a new message port.
  1216. PROC makeport()
  1217.   DEF port:PTR TO mp
  1218.   IF (port:=CreateMsgPort())=NIL THEN RaiseX("GUI",1065,'Could not create message port. Run out of signal bits?')
  1219. ENDPROC port
  1220.  
  1221. -> Clean initialisation stuff and reset handle.
  1222. PROC cleaninit(gh:PTR TO guihandle)
  1223.   -> Clean ports.
  1224. #ifdef EASY_APPWINDOW
  1225. #ifdef EASY_EXTRAS
  1226.   IF (gh.mh=NIL) AND gh.awport THEN DeleteMsgPort(gh.awport)
  1227. #endif
  1228. #ifndef EASY_EXTRAS
  1229.   IF gh.awport THEN DeleteMsgPort(gh.awport)
  1230. #endif
  1231.   gh.awport:=NIL
  1232.   IF gh.wb_isopen
  1233.     CloseLibrary(workbenchbase)
  1234.     gh.wb_isopen:=FALSE
  1235.   ENDIF
  1236. #endif
  1237. #ifdef EASY_EXTRAS
  1238.   IF (gh.mh=NIL) AND gh.wndport THEN DeleteMsgPort(gh.wndport)
  1239. #endif
  1240. #ifndef EASY_EXTRAS
  1241.   IF gh.wndport THEN DeleteMsgPort(gh.wndport)
  1242. #endif
  1243.   gh.wndport:=NIL
  1244.   IF gh.gt_isopen
  1245.     CloseLibrary(gadtoolsbase)
  1246.     gh.gt_isopen:=FALSE
  1247.   ENDIF
  1248. ENDPROC
  1249.  
  1250. /********** cleangui() **********/
  1251. EXPORT PROC cleangui(gh:PTR TO guihandle)
  1252.   DEF f
  1253.   IF gh
  1254.     -> Close window if necessary.
  1255.     closewin(gh)
  1256.     IF f:=gh.onclean THEN f(gh.info)
  1257.     cleaninit(gh)
  1258. #ifdef EASY_EXTRAS
  1259.     IF gh.mh
  1260.       -> Unlink from multi-window list.
  1261.       Remove(gh.link)
  1262.       gh.mh:=NIL
  1263.     ENDIF
  1264. #endif
  1265.     END gh
  1266.   ENDIF
  1267. ENDPROC
  1268.  
  1269. /********** closewin() **********/
  1270. EXPORT PROC closewin(gh:PTR TO guihandle)
  1271.   DEF w:PTR TO window
  1272.   IF w:=gh.wnd
  1273.     -> Remember window size and position.
  1274.     gh.x:=w.leftedge
  1275.     gh.y:=w.topedge
  1276.     gh.xsize:=w.width
  1277.     gh.ysize:=w.height
  1278. #ifdef EASY_EXTRAS
  1279.     gh.blockcnt:=1  -> Force unblock, if necessary.
  1280.     unblockwin(gh)  -> Just in case!
  1281. #endif
  1282.     removegui(gh)
  1283.     removemenus(gh)
  1284. #ifdef EASY_APPWINDOW
  1285.     IF gh.appwin
  1286.       RemoveAppWindow(gh.appwin)
  1287.       gh.appwin:=NIL
  1288.     ENDIF
  1289.     -> Remove any last minute messages safely.
  1290.     IF gh.awport THEN clearmsgs(gh.awport,{testappwmsg},gh)
  1291. #endif
  1292.     IF w
  1293.       -> Must be in Forbid()/Permit() brackets.
  1294.       Forbid()
  1295.       -> Remove any last minute messages safely.
  1296.       clearmsgs(gh.wndport,{testintuimsg},w)
  1297.       -> Make sure no more messages get sent.
  1298.       w.userport:=NIL
  1299.       ModifyIDCMP(w,0)
  1300.       Permit()
  1301.       -> Now the window can be closed safely.
  1302.       CloseWindow(w)
  1303.       gh.pwnd:=NIL
  1304.     ENDIF
  1305.     stdrast:=NIL
  1306.     IF gh.visual
  1307.       FreeVisualInfo(gh.visual)
  1308.       gh.visual:=NIL
  1309.     ENDIF
  1310. #ifdef EASY_EXTRAS
  1311.     -> If multi then decrement count of open windows.
  1312.     IF gh.mh THEN gh.mh.opencount:=gh.mh.opencount-1
  1313. #endif
  1314.     IF gh.is_wb
  1315.       IF gh.scr THEN UnlockPubScreen(NIL,gh.scr)
  1316.       gh.scr:=NIL
  1317.     ENDIF
  1318.     -> If the font is linked to the screen, it's no longer valid.
  1319.     IF gh.ta_scr THEN gh.tattr:=NIL
  1320.   ENDIF
  1321. ENDPROC
  1322.  
  1323. -> Render the gadgets on the window.
  1324. PROC rendergui(gh:PTR TO guihandle)
  1325.   DEF glist=0,w:PTR TO window,base:PTR TO g
  1326.   w:=gh.pwnd
  1327.   base:=gh.base
  1328.   gh.gl:=CreateContext({glist})
  1329.   IF gh.gl=NIL THEN RaiseX("GUI",1183,'Could not create gadget context. Out of memory?')
  1330.   stdrast:=w.rport
  1331.   -> Adjust intermediate gadgets to be real gadgets fitting in window.
  1332.   adjust(base, gh.xoff,gh.yoff,
  1333.          w.width-gh.xsize+base.xs,w.height-gh.ysize+base.ys, gh)
  1334.   AddGList(w,glist,-1,-1,NIL)
  1335. #ifndef EASY_KEYBOARD
  1336.   -> If no keyboard support, activate first sting gadget.
  1337.   IF gh.firststr THEN ActivateGadget(gh.firststr,w,NIL)
  1338. #endif
  1339.   RefreshGList(glist,w,NIL,-1)
  1340.   Gt_RefreshWindow(w,NIL)
  1341.   -> Set public pointer, as a flag to say it's OK to play with the GUI, now.
  1342.   gh.wnd:=w
  1343. ENDPROC glist
  1344.  
  1345. -> Remove PLUGINs and gadgets from window.
  1346. PROC removegads(gh:PTR TO guihandle)
  1347.   DEF pl:PTR TO plugin
  1348.   -> Set public pointer to NIL, to say it's no longer safe to play with the GUI.
  1349.   gh.wnd:=NIL
  1350.   pl:=gh.plugins
  1351.   WHILE pl
  1352.     pl.clear_render(gh.pwnd)
  1353.     pl:=pl.next
  1354.   ENDWHILE
  1355.   IF gh.glist
  1356.     RemoveGList(gh.pwnd,gh.glist,-1)
  1357.     FreeGadgets(gh.glist)
  1358.   ENDIF
  1359. ENDPROC
  1360.  
  1361. -> Decide what the real screen bottom is by getting size gadget height.
  1362. PROC getrealbot(s:PTR TO screen)
  1363.   DEF dri,bot,im:PTR TO image
  1364.   bot:=s.wborbottom
  1365.   IF dri:=GetScreenDrawInfo(s)
  1366.     IF im:=NewObjectA(NIL,'sysiclass',
  1367.                      [SYSIA_DRAWINFO,dri, SYSIA_WHICH,SIZEIMAGE,
  1368.                       SYSIA_SIZE,SysISize(s.flags), NIL])
  1369.       bot:=im.height
  1370.       DisposeObject(im)
  1371.     ENDIF
  1372.     FreeScreenDrawInfo(s,dri)
  1373.   ENDIF
  1374. ENDPROC bot
  1375.  
  1376. #ifdef EASY_KEYBOARD
  1377. -> Fiddled so actually one less than length...
  1378. PROC execlistlen(list:PTR TO mlh)
  1379.   DEF len=-1, node:PTR TO mln
  1380.   -> Catch the case where the LISTV is being cleanly updated.
  1381.   IF list<>-1
  1382.     IF list
  1383.       node:=list.head
  1384.       WHILE node:=node.succ DO len++
  1385.     ENDIF
  1386.   ENDIF
  1387. ENDPROC len
  1388.  
  1389. -> Do action appropriate to key press.
  1390. PROC performkey(gh:PTR TO guihandle,code)
  1391.   DEF list:PTR TO LONG,ret,val,tag,index,data,gad=NIL:PTR TO gadget,inc
  1392.   -> Look up gadget in key index.
  1393.   IF islower(code)      -> Positive action
  1394.     gad:=gh.keys[code-"a"]
  1395.     inc:=TRUE
  1396.   ELSEIF isupper(code)  -> Negative action
  1397.     gad:=gh.keys[code-"A"]
  1398.     inc:=FALSE
  1399.   ENDIF
  1400.   IF gad=NIL THEN RETURN GUI_CONT
  1401. /* Ack! Doesn't work under OS2.0...
  1402. #ifdef EASY_EXTRAS
  1403.   Gt_GetGadgetAttrsA(gad,gh.pwnd,NIL,[GA_DISABLED,{ret},NIL])
  1404.   IF ret THEN RETURN GUI_CONT
  1405. #endif
  1406. */
  1407.   list:=gad.userdata
  1408.   ret:=ATTR(list,EG_ACT)
  1409. #ifdef EASY_EXTRAS
  1410.   -> If disabled then don't react.
  1411.   IF optdis(gad.gadgetid,list) THEN RETURN GUI_CONT
  1412. #endif
  1413.   -> Tag is TRUE if a button.
  1414.   data,tag:=indexdata(gad.gadgetid)
  1415.   data:=OptDefATTR(list,data)
  1416.   SELECT MAXGUI OF gad.gadgetid
  1417.   -> Just press button.
  1418.   -> CASE BUTTON,SBUTTON,RBUTTON
  1419.   CASE STR,INTEGER
  1420.     -> Activate string and integer gadgets.
  1421.     ActivateGadget(gad,gh.pwnd,NIL)
  1422.   CASE CHECK
  1423.     -> Toggle check gadgets.
  1424.     tag:=GTCB_CHECKED
  1425.     index:=CHK_VAL
  1426.     val:=(IsChecked(gad)=FALSE)
  1427.   CASE MX
  1428.     -> Next/prev item, wrapping.
  1429.     tag:=GTMX_ACTIVE
  1430.     index:=ListLen(ATTR(list,MX_LIST))-2
  1431.     val:=ATTR(list,MX_CURR)
  1432.     IF inc
  1433.       IF val++>=index THEN val:=0
  1434.     ELSE
  1435.       IF val--<0 THEN val:=index
  1436.     ENDIF
  1437.     index:=MX_CURR
  1438.   CASE CYCLE
  1439.     -> Next/prev item, wrapping.
  1440.     tag:=GTCY_ACTIVE
  1441.     index:=ListLen(ATTR(list,CYC_LIST))-2
  1442.     val:=ATTR(list,CYC_CURR)
  1443.     IF inc
  1444.       IF val++>=index THEN val:=0
  1445.     ELSE
  1446.       IF val--<0 THEN val:=index
  1447.     ENDIF
  1448.     index:=CYC_CURR
  1449.   CASE SCROLL
  1450.     -> Inc/dec, stopping at ends.
  1451.     tag:=GTSC_TOP
  1452.     val:=ATTR(list,SCR_TOP)
  1453.     IF inc
  1454.       IF val++>=(ATTR(list,SCR_TOTL)-ATTR(list,SCR_VIS)) THEN tag:=0
  1455.     ELSE
  1456.       IF val--<0 THEN tag:=0
  1457.     ENDIF
  1458.     index:=SCR_TOP
  1459.   CASE SLIDE
  1460.     -> Inc/dec, stopping at ends.
  1461.     tag:=GTSL_LEVEL
  1462.     val:=ATTR(list,SLI_CURR)
  1463.     IF inc
  1464.       IF val++>=ATTR(list,SLI_MAX) THEN tag:=0
  1465.     ELSE
  1466.       IF val--<ATTR(list,SLI_MIN) THEN tag:=0
  1467.     ENDIF
  1468.     index:=SLI_CURR
  1469.   CASE LISTV
  1470.     -> Next/prev, stopping at ends.
  1471.     tag:=GTLV_SELECTED
  1472.     val:=ATTR(list,LST_CURR)
  1473.     IF inc
  1474.       IF val++>=execlistlen(ATTR(list,LST_LIST)) THEN tag:=0
  1475.     ELSE
  1476.       IF val--<0 THEN tag:=0
  1477.     ENDIF
  1478.     index:=LST_CURR
  1479.   CASE PALETTE
  1480.     -> Next/prev, wrapping.
  1481.     tag:=GTPA_COLOR
  1482.     val:=ATTR(list,PAL_CURR)
  1483.     index:=Shl(1,ATTR(list,PAL_DEP))-1
  1484.     IF inc
  1485.       IF val++>=index THEN val:=0
  1486.     ELSE
  1487.       IF val--<0 THEN val:=index
  1488.     ENDIF
  1489.     index:=PAL_CURR
  1490.   ENDSELECT
  1491.   -> Perform change if required.
  1492.   IF tag
  1493.     IF tag<>TRUE  -> If not a button (non-zero is tag value).
  1494.       setgadattr(gad,gh.pwnd,list,val,tag,index)
  1495.       IF gad.gadgetid=LISTV THEN setgadattr(gad,gh.pwnd,list,val,GTLV_MAKEVISIBLE)
  1496.     ENDIF
  1497.     -> Do action.
  1498.     IF IsActionFun(ret)
  1499.       -> If button (non-zero is tag value).
  1500.       IF tag=TRUE THEN ret(0,data,gh.info) ELSE ret(0,data,gh.info,val)
  1501.       ret:=GUI_CONT
  1502.     ENDIF
  1503.   ELSE
  1504.     ret:=GUI_CONT
  1505.   ENDIF
  1506. ENDPROC ret
  1507. #endif
  1508.  
  1509. -> Call action function based on new code.
  1510. PROC performaction(fun,gad:PTR TO gadget,info,code,l:PTR TO LONG,qual)
  1511.   DEF data,but,val
  1512.   data,but,val:=indexdata(gad.gadgetid)
  1513.   data:=OptDefATTR(l,data)
  1514. ENDPROC (IF but THEN fun(qual,data,info) ELSE
  1515.                      fun(qual,data,info,IF val THEN ATTR(l,val) ELSE code))
  1516.  
  1517. /********** getstr **********/
  1518. EXPORT PROC getstr(gh,g) IS gadstr(g,findgadget(gh,g))
  1519.  
  1520. /********** getinteger **********/
  1521. EXPORT PROC getinteger(gh,g) IS gadinteger(g,findgadget(gh,g))
  1522.  
  1523. -> Copy buffer string to gadget E-string.
  1524. PROC gadstr(l:PTR TO LONG, gad:PTR TO gadget) IS
  1525.   IF gad THEN StrCopy(ATTR(l,STR_STR),GadString(gad)) ELSE 0
  1526.  
  1527. -> Copy buffer integer to gadget integer.
  1528. PROC gadinteger(l:PTR TO LONG, gad:PTR TO gadget)
  1529.   DEF x=0
  1530.   IF gad THEN ATTR(l,INT_VAL):=x:=GadLongInt(gad)
  1531. ENDPROC x
  1532.  
  1533. -> Record new gadget value.
  1534. PROC performset(gad:PTR TO gadget,code,l:PTR TO LONG)
  1535.   SELECT MAXGUI OF gad.gadgetid
  1536.   CASE STR;     gadstr(l,gad)
  1537.   CASE INTEGER; gadinteger(l,gad)
  1538.   CASE CHECK;   ATTR(l,CHK_VAL):=IsChecked(gad)
  1539.   CASE MX;      ATTR(l,MX_CURR):=code
  1540.   CASE CYCLE;   ATTR(l,CYC_CURR):=code
  1541.   CASE SCROLL;  ATTR(l,SCR_TOP):=code
  1542.   CASE SLIDE;   ATTR(l,SLI_CURR):=code
  1543.   CASE LISTV;   ATTR(l,LST_CURR):=code
  1544.   CASE PALETTE; ATTR(l,PAL_CURR):=code
  1545.   ENDSELECT
  1546. ENDPROC
  1547.  
  1548. -> Clean gadget description objects.
  1549. PROC clean(base:PTR TO g)
  1550.   DEF i:PTR TO g,j
  1551.   IF base
  1552.     IF IsRowOrCol(base.type)
  1553.       i:=base.list
  1554.       WHILE i
  1555.         j:=i
  1556.         i:=i.next
  1557.         clean(j)
  1558.       ENDWHILE
  1559.     ELSEIF IsBevel(base.type)
  1560.       clean(base.list)
  1561.     ENDIF
  1562.     END base
  1563.   ENDIF
  1564. ENDPROC
  1565.  
  1566. -> Length of text, ignoring a "_" if present.
  1567. #ifdef EASY_KEYBOARD
  1568. #define textlenkey(s,g,k) textlen_key(s,g,k)
  1569. #endif
  1570. #ifndef EASY_KEYBOARD
  1571. #define textlenkey(s,g,k) textlen(s,g)
  1572. #endif
  1573.  
  1574. -> Calculate minimum size for a PALETTE gadget showing depth d
  1575. -> Ack! Fiddled to compensate for OS2.0 indicator
  1576. PROC min_pal(x,y,d)
  1577.   DEF dy
  1578.   IF (x+y)=0 THEN RETURN RaiseX("Egui",1441,'Bad PALETTE gadget sizes.')
  1579.   dy:=Div(Mul(y,d),x+y)
  1580. ENDPROC Max(Mul(Shl(1,d-dy),7)+21,x), Max(Shl(4,dy)+3,y)
  1581.  
  1582. -> Calculate minimum size of GUI.
  1583. PROC minsize(gui:PTR TO LONG,gh:PTR TO guihandle,isinrows=TRUE,eql=FALSE)
  1584.   DEF p:PTR TO g,h,minargs,a,b:PTR TO LONG,c,pl:PTR TO plugin,type,
  1585.       ta:PTR TO textattr
  1586.   minargs:=minARGS()
  1587.   ta:=gh.tattr
  1588.   h:=ta.ysize
  1589.   type:=ATTR(gui,EG_TYPE)
  1590.   IF (type<0) OR (type>=MAXGUI) THEN RaiseX("Egui",gui,'Bad gadget type.')
  1591.   IF (ListLen(gui)<minargs[type]) THEN RaiseX("Egui",gui,'Too few arguments for gadget.')
  1592. #ifdef EASY_KEYBOARD
  1593.   a:=optkey(type,gui)
  1594. #endif
  1595. #ifndef EASY_KEYBOARD
  1596.   a:=0
  1597. #endif
  1598.   SELECT MAXGUI OF type
  1599.   CASE ROWS,EQROWS,COLS,EQCOLS
  1600.     p:=foreach(gui,type,gh,IsRow(type),IsEqualGroup(type))
  1601.   CASE BEVEL,BEVELR
  1602.     p:=minsize(ATTR(gui,BEV_GUI),gh)
  1603.     p:=newg(BEVELXSPACE*2+p.xs,BEVELYSPACE*2+p.ys,type,p,p.flags)
  1604.   CASE BUTTON,SBUTTON,RBUTTON
  1605.     p:=newg(textlenkey(ATTR(gui,BUT_TXT),ta,a)+BUTXSPACE,
  1606.             h+BUTYSPACE,type,gui,ButtSpFlags(type))
  1607.   CASE CHECK
  1608.     a:=textlenkey(ATTR(gui,CHK_TXT),ta,a)+8
  1609.     p:=newg(11+a+BUTXSPACE,h+CHECKSPACE,CHECK,gui,
  1610.             IF eql THEN COND_RESIZEX ELSE 0,IF ATTR(gui,CHK_LEFT) THEN a ELSE 0)
  1611.   CASE INTEGER
  1612.     a:=textlenkey(ATTR(gui,INT_TXT),ta,a)+8
  1613.     p:=newg(ATTR(gui,INT_REL)*textlen('5',ta)+a,h+BUTYSPACE,INTEGER,gui,
  1614.             RESIZEX,a)
  1615.   CASE LISTV
  1616.     a:=textlen(ATTR(gui,LST_TXT),ta)
  1617.     p:=newg(Max(a,ATTR(gui,LST_RELX)*h+4),
  1618.             ATTR(gui,LST_RELY)*h+(IF a THEN (h+10) ELSE 4),LISTV,gui,
  1619.             RESIZEXANDY)
  1620.   CASE MX
  1621.     c:=textlenkey(ATTR(gui,MX_TXT),ta,a)+8
  1622.     a:=0
  1623.     b:=ATTR(gui,MX_LIST)
  1624.     WHILE b[] DO a:=Max(a,textlen(b[]++,ta))
  1625.     p:=newg(8+a+c+BUTXSPACE,ListLen(ATTR(gui,MX_LIST))-1*(h+MXSPACE)-1,MX,gui,
  1626.             IF eql THEN COND_RESIZEX ELSE 0,IF ATTR(gui,MX_LEFT) THEN c ELSE 0)
  1627.   CASE CYCLE
  1628.     c:=textlenkey(ATTR(gui,CYC_TXT),ta,a)+8
  1629.     a:=0
  1630.     b:=ATTR(gui,CYC_LIST)
  1631.     WHILE b[] DO a:=Max(a,textlen(b[]++,ta))
  1632.     p:=newg(h*2+a+c+BUTXSPACE,h+BUTYSPACE,CYCLE,gui,RESIZEX,c)
  1633.   CASE PALETTE
  1634.     a:=textlenkey(ATTR(gui,PAL_TXT),ta,a)+8
  1635.     b,c:=min_pal(ATTR(gui,PAL_RELX)*h,ATTR(gui,PAL_RELY)*h,ATTR(gui,PAL_DEP))
  1636.     p:=newg(b+a,c,PALETTE,gui,RESIZEXANDY,a)
  1637.   CASE SCROLL
  1638.     a:=ATTR(gui,SCR_REL)*h
  1639.     b:=h+BUTYSPACE
  1640.     p:=newg(IF ATTR(gui,SCR_VERT) THEN b ELSE a,
  1641.             IF ATTR(gui,SCR_VERT) THEN a ELSE b,SCROLL,gui,
  1642.             IF ATTR(gui,SCR_VERT) THEN RESIZEY ELSE RESIZEX)
  1643.   CASE SLIDE
  1644.     a:=textlenkey(ATTR(gui,SLI_TXT),ta,a)+8
  1645.     b:=ATTR(gui,SLI_REL)*h
  1646.     c:=h+BUTYSPACE
  1647.     p:=newg(a+IF ATTR(gui,SLI_VERT) THEN c ELSE b,
  1648.             IF ATTR(gui,SLI_VERT) THEN b ELSE c,SLIDE,gui,
  1649.             IF ATTR(gui,SLI_VERT) THEN RESIZEY ELSE RESIZEX,a)
  1650.   CASE STR
  1651.     a:=textlenkey(ATTR(gui,STR_TXT),ta,a)+8
  1652.     p:=newg(ATTR(gui,STR_REL)*h+a,h+BUTYSPACE,STR,gui,RESIZEX,a)
  1653.   CASE TEXT,NUM
  1654.     a:=textlen(ATTR(gui,TXT_TXT),ta)+8
  1655.     b:=(IF type=NUM THEN Max(ATTR(gui,NUM_REL),2)*textlen('5',ta)
  1656.         ELSE Max(textlen(ATTR(gui,TXT_VAL),ta),ATTR(gui,TXT_REL)*h))
  1657.     p:=newg(a+b,h+IF ATTR(gui,TXT_BORD) THEN BUTYSPACE ELSE YSP,type,gui,
  1658.             RESIZEX,a)
  1659.   CASE BAR
  1660.     p:=newg(2,4,BAR,gui,IF isinrows THEN COND_RESIZEX ELSE COND_RESIZEY)
  1661.   CASE SPACEH,SPACE,SPACEV
  1662.     p:=newg(0,0,SPACE,gui,SpaceFlags(type))
  1663.   CASE PLUGIN
  1664.     IF (pl:=ATTR(gui,PLG_OBJ))=NIL THEN RaiseX("Egui",gui,'PLUGIN object is NIL.')
  1665.     a,b:=pl.min_size(ta,h)
  1666.     p:=newg(a,b,PLUGIN,gui,pl.will_resize())
  1667.     pl.next:=gh.plugins; gh.plugins:=pl
  1668.     pl.base:=p
  1669.     pl.gh:=gh
  1670.   ENDSELECT
  1671. ENDPROC p
  1672.  
  1673. -> Calculate minimum size of group.
  1674. PROC foreach(guilist:PTR TO LONG,type,gh:PTR TO guihandle,row,eq)
  1675.   DEF l,x=0,y=0,z=0,zmid=NO_MID,zother=0,a,p:PTR TO g,list=NIL,
  1676.       last:PTR TO g,resize=0,xs,t
  1677.   last:={list}
  1678.   l:=ListLen(guilist)-1
  1679.   FOR a:=1 TO l
  1680.     p:=minsize(guilist[a],gh,row,eq)
  1681.     resize:=resize OR p.flags
  1682.     xs:=p.xs
  1683.     IF row
  1684.       x:=Max(xs,x)
  1685.       y:=y+p.ys+IF y THEN YSPACING ELSE 0
  1686.     ELSE
  1687.       y:=Max(p.ys,y)
  1688.       x:=x+xs+IF x THEN XSPACING ELSE 0
  1689.     ENDIF
  1690.     z:=Max(z,xs)        -> for EQ(ROWS/COLS)
  1691.     t:=p.mid
  1692.     zmid:=Max(zmid,t)
  1693.     zother:=Max(zother,IF t<>NO_MID THEN (xs-t) ELSE xs)
  1694.     last.next:=p
  1695.     last:=p
  1696.   ENDFOR
  1697.   IF eq
  1698.     last:=list
  1699.     z:=IF zmid<>NO_MID THEN (zmid+zother) ELSE zother
  1700.     WHILE last
  1701.       last.xs:=z
  1702.       last.mid:=IF last.mid<>NO_MID THEN zmid ELSE 0
  1703.       last:=last.next
  1704.     ENDWHILE
  1705.     x:=IF row THEN z ELSE (z+XSPACING*l-XSPACING)
  1706.   ENDIF
  1707.   resize:=(IF DoesXUncond(resize) THEN RESIZEX ELSE 0) OR
  1708.           (IF DoesYUncond(resize) THEN RESIZEY ELSE 0)
  1709. ENDPROC newg(x,y,type,list,resize)
  1710.  
  1711. -> Calculate real positions and sizes, and create real gadgets.
  1712. PROC adjust(base:PTR TO g,x,y,xs,ys,gh:PTR TO guihandle,isinrow=TRUE)
  1713.   DEF pl:PTR TO plugin
  1714.   IF DoesXResize(base.flags)=FALSE THEN (x:=xs-base.xs/2+x) BUT xs:=base.xs
  1715.   IF DoesYResize(base.flags)=FALSE THEN (y:=ys-base.ys/2+y) BUT ys:=base.ys
  1716.   SELECT MAXGUI OF base.type
  1717.   CASE ROWS,EQROWS,COLS,EQCOLS
  1718.     adjustall(base,x,y,xs,ys,gh)
  1719.   CASE BEVEL,BEVELR
  1720.     adjust(base.list,BEVELXSPACE+x,BEVELYSPACE+y,
  1721.            xs-(BEVELXSPACE*2),ys-(BEVELYSPACE*2),gh)
  1722.     DrawBevelBoxA(gh.pwnd.rport,x,y,xs,ys,
  1723.                  [GT_VISUALINFO,gh.visual,GTBB_FRAMETYPE,BBFT_BUTTON,
  1724.                   IF base.type=BEVELR THEN GTBB_RECESSED ELSE TAG_IGNORE,0,NIL])
  1725.   CASE BAR
  1726.     IF isinrow
  1727.       Line(x,y+1,x+xs-1,y+1,1)
  1728.       Line(x,y+2,x+xs-1,y+2,2)
  1729.     ELSE
  1730.       Line(x+1,y,x+1,y+ys-1,1)
  1731.       Line(x+2,y,x+2,y+ys-1,2)
  1732.     ENDIF
  1733.   CASE PLUGIN
  1734.     pl:=ATTR(base.list,PLG_OBJ)
  1735.     pl.x:=x; pl.y:=y; pl.xs:=xs; pl.ys:=ys
  1736.     IF OptATTR(base.list,PLG_GT)
  1737.       gh.gl:=pl.gtrender(gh.gl,gh.visual,gh.tattr,x,y,xs,ys,gh.pwnd)
  1738.     ELSE
  1739.       pl.render(gh.tattr,x,y,xs,ys,gh.pwnd)
  1740.     ENDIF
  1741.   DEFAULT
  1742.     base.x:=x; base.y:=y
  1743.     creategadget(base,xs,ys,gh)
  1744.   ENDSELECT
  1745. ENDPROC x+xs+XSPACING,y+ys+YSPACING
  1746.  
  1747. -> adjust over column and row groups.
  1748. PROC adjustall(base:PTR TO g,x,y,xs,ys,gh)
  1749.   DEF p:PTR TO g,rs=0,fs=0,sp=0,ds=0,t,rg=0,u,row
  1750.   -> fs is fixed-width total, rs is resize total
  1751.   -> ds is gad count, sp is space gad count
  1752.   p:=base.list
  1753.   row:=IsRow(base.type)
  1754.   WHILE p
  1755.     t:=IF row THEN p.ys ELSE p.xs
  1756.     IF (row AND DoesYResize(p.flags)) OR (row=FALSE AND DoesXResize(p.flags))
  1757.       IF t<=0 THEN sp++ ELSE ((rs:=rs+t) BUT rg++)
  1758.     ELSE
  1759.       fs:=fs+t
  1760.     ENDIF
  1761.     p:=p.next
  1762.     ds++
  1763.   ENDWHILE
  1764.   p:=base.list
  1765.   ds:=(IF row THEN ys ELSE xs)-rs-fs-(ds-1*IF row THEN YSPACING ELSE XSPACING)
  1766.   -> ds is now difference in space reqts
  1767.   WHILE p
  1768.     t:=IF row THEN p.ys ELSE p.xs
  1769.     IF (row AND DoesYResize(p.flags)) OR (row=FALSE AND DoesXResize(p.flags))
  1770.       IF t<=0
  1771.         IF rg
  1772.           IF row THEN ys:=0 ELSE xs:=0
  1773.         ELSE  -> If only space gads can resize...
  1774.           fs:=((sp-1)/2+ds)/sp  -> Share space completely and fairly
  1775.           ds:=ds-fs
  1776.           sp--
  1777.           IF row THEN ys:=fs ELSE xs:=fs
  1778.         ENDIF
  1779.       ELSE
  1780.         fs:=((t*ds)+((rs-1)/2))/rs  -> Share space completely and fairly
  1781.         ds:=ds-fs
  1782.         rs:=rs-t
  1783.         IF row THEN ys:=t+fs ELSE xs:=t+fs
  1784.       ENDIF
  1785.     ELSE
  1786.       IF row THEN ys:=t ELSE xs:=t
  1787.     ENDIF
  1788.     t,u:=adjust(p,x,y,xs,ys,gh,row)
  1789.     IF row THEN y:=u ELSE x:=t
  1790.     p:=p.next
  1791.   ENDWHILE
  1792. ENDPROC
  1793.  
  1794. -> Create real gadget.
  1795. PROC creategadget(base:PTR TO g,lxs,lys,gh:PTR TO guihandle)
  1796.   DEF tl,i:PTR TO LONG,minargs,text,flags=0,kindtab,h,textl,x,y,xs,ys,
  1797.       mid,domid=FALSE,key=0,appw=0
  1798.   minargs:=minARGS()
  1799.   -> Args at least two, so not SPACE* (never called for other possibilities)
  1800.   IF minargs[base.type]>=2
  1801.     i:=base.list
  1802.     h:=gh.tattr.ysize
  1803.     flags:=PLACETEXT_RIGHT
  1804.     x:=base.x
  1805.     y:=base.y
  1806.     xs:=base.xs
  1807.     ys:=base.ys
  1808.     mid:=IF (base.mid<>NO_MID) AND base.mid THEN (base.mid) ELSE 0
  1809.     text:=ATTR(i,EG_TXT)  -> speculative
  1810.     IF text=NIL THEN text:=''
  1811.     SELECT MAXGUI OF base.type
  1812.     CASE BUTTON,SBUTTON,RBUTTON
  1813.       tl:=[NIL]
  1814.       flags:=PLACETEXT_IN
  1815.       IF HasHButtSp(base.type) THEN xs:=lxs
  1816.       IF HasVButtSp(base.type) THEN ys:=lys
  1817. #ifdef EASY_APPWINDOW
  1818.       appw:=OptATTR(i,BUT_APPW)
  1819. #endif
  1820.     CASE CHECK
  1821.       tl:=[GTCB_CHECKED,IF ATTR(i,CHK_VAL) THEN 1 ELSE 0, GTCB_SCALED,TRUE, NIL]
  1822.       textl:=IF StrLen(text) THEN mid ELSE 0
  1823.       x:=x+textl
  1824.       IF ATTR(i,CHK_LEFT) THEN flags:=PLACETEXT_LEFT
  1825.       xs:=h*2+2
  1826.       ys:=h+1
  1827.     CASE LISTV
  1828.       xs:=ATTR(i,LST_CURR)
  1829.       tl:=[GTLV_LABELS,ATTR(i,LST_LIST), GTLV_SELECTED,xs,
  1830.            IF ATTR(i,LST_SHOW)>=1 THEN GTLV_SHOWSELECTED ELSE TAG_IGNORE,NIL,
  1831.            -> GTLV_SCROLLWIDTH,h*2,
  1832.            GTLV_READONLY,ATTR(i,LST_RO),
  1833. ->           IF xs<>-1 THEN GTLV_TOP ELSE TAG_IGNORE, xs,
  1834.            IF xs<>-1 THEN GTLV_MAKEVISIBLE ELSE TAG_IGNORE, xs, NIL]
  1835.       flags:=PLACETEXT_ABOVE
  1836.       xs:=lxs
  1837.       IF StrLen(text)
  1838.         ys:=lys-h-6
  1839.         y:=y+h+6
  1840.       ELSE
  1841.         ys:=lys
  1842.       ENDIF
  1843. #ifdef EASY_APPWINDOW
  1844.       appw:=OptATTR(i,LST_APPW)
  1845. #endif
  1846.     CASE MX
  1847.       tl:=[GTMX_LABELS,ATTR(i,MX_LIST), GTMX_ACTIVE,ATTR(i,MX_CURR),
  1848.            GTMX_TITLEPLACE,IF ATTR(i,MX_LEFT) THEN PLACETEXT_LEFT ELSE PLACETEXT_RIGHT,
  1849.            GTMX_SPACING,MXSPACE, GTMX_SCALED,TRUE, NIL]
  1850.       textl:=IF StrLen(text) THEN mid ELSE 0
  1851.       x:=x+textl
  1852.       IF ATTR(i,MX_LEFT)=FALSE THEN flags:=PLACETEXT_RIGHT
  1853.       xs:=h
  1854.       ys:=h
  1855.     CASE STR
  1856.       tl:=[GTST_STRING,ATTR(i,STR_STR), STRINGA_REPLACEMODE,OptATTR(i,STR_OVR),
  1857.            GTST_MAXCHARS,Min(StrMax(ATTR(i,STR_STR)),ATTR(i,STR_MAX)), NIL]
  1858.       domid:=TRUE
  1859. #ifdef EASY_APPWINDOW
  1860.       appw:=OptATTR(i,STR_APPW)
  1861. #endif
  1862.     CASE INTEGER
  1863.       tl:=[GTIN_NUMBER,ATTR(i,INT_VAL), GTIN_MAXCHARS,15, NIL]
  1864.       domid:=TRUE
  1865.       lxs--
  1866.     CASE CYCLE
  1867.       tl:=[GTCY_LABELS,ATTR(i,CYC_LIST), GTCY_ACTIVE,ATTR(i,CYC_CURR), NIL]
  1868.       domid:=TRUE
  1869.     CASE PALETTE
  1870.       -> Ack!  Indicator width is large for OS2.0 compatibility
  1871.       tl:=[GTPA_DEPTH,ATTR(i,PAL_DEP), GTPA_INDICATORWIDTH,16,
  1872.            GTPA_COLOR,ATTR(i,PAL_CURR), NIL]
  1873.       domid:=TRUE
  1874.     CASE SCROLL
  1875.       tl:=[GTSC_TOP,ATTR(i,SCR_TOP), GTSC_TOTAL,ATTR(i,SCR_TOTL),
  1876.            PGA_FREEDOM,IF ATTR(i,SCR_VERT) THEN LORIENT_VERT ELSE LORIENT_HORIZ,
  1877.            GTSC_VISIBLE,ATTR(i,SCR_VIS), GTSC_ARROWS,12, NIL]
  1878.       xs:=lxs
  1879.       ys:=lys
  1880.       text:=''
  1881.     CASE SLIDE
  1882.       tl:=[GTSL_MIN,ATTR(i,SLI_MIN), GTSL_MAX,ATTR(i,SLI_MAX),
  1883.            GTSL_LEVEL,ATTR(i,SLI_CURR), GTSL_LEVELFORMAT,ATTR(i,SLI_FMT),
  1884.            PGA_FREEDOM,IF ATTR(i,SLI_VERT) THEN LORIENT_VERT ELSE LORIENT_HORIZ,
  1885.            GTSL_MAXLEVELLEN,3, NIL]
  1886.       domid:=TRUE
  1887.     CASE TEXT
  1888.       tl:=[GTTX_TEXT,ATTR(i,TXT_VAL), GTTX_BORDER,ATTR(i,TXT_BORD), NIL]
  1889.       domid:=TRUE
  1890.     CASE NUM
  1891.       tl:=[GTNM_NUMBER,ATTR(i,NUM_VAL), GTNM_BORDER,ATTR(i,NUM_BORD), NIL]
  1892.       domid:=TRUE
  1893.     ENDSELECT
  1894.     IF domid
  1895.       flags:=PLACETEXT_LEFT
  1896.       textl:=IF StrLen(text) THEN mid ELSE 0
  1897. ->      textl:=IF mid<>NO_MID THEN mid ELSE 0
  1898.       x:=x+textl
  1899.       xs:=lxs-textl
  1900.       ys:=lys
  1901.     ENDIF
  1902. #ifdef EASY_KEYBOARD
  1903.     key:=optkey(base.type,i)
  1904. #endif
  1905.     kindtab:=kindTAB()
  1906.     gh.gl:=CreateGadgetA(kindtab[base.type],gh.gl,
  1907.         [x,y,xs,ys,text,gh.tattr,base.type,flags,gh.visual,NIL]:newgadget,
  1908.         [IF key THEN GT_UNDERSCORE ELSE TAG_IGNORE,"_",
  1909.          IF optdis(base.type,i) THEN GA_DISABLED ELSE TAG_IGNORE,TRUE,
  1910.          TAG_MORE,tl])
  1911.     IF gh.gl=NIL THEN RaiseX("GUI",i,'Could not create gadget. Out of memory?')
  1912.     gh.gl.userdata:=i
  1913. #ifdef EASY_APPWINDOW
  1914.     IF appw THEN gh.gl.mutualexclude:=EG_MAGIC -> AppW magic identifier.
  1915. #endif
  1916. #ifndef EASY_KEYBOARD
  1917.     IF base.type=STR THEN IF gh.firststr=NIL THEN gh.firststr:=gh.gl
  1918. #endif
  1919. #ifdef EASY_KEYBOARD
  1920.     -> Remember gadget in key index.  Key must be lowercase.
  1921.     IF islower(key) THEN gh.keys[key-"a"]:=gh.gl
  1922. #endif
  1923.   ENDIF
  1924. ENDPROC
  1925.  
  1926. /********** findgadget **********/
  1927. EXPORT PROC findgadget(gh:PTR TO guihandle,list)
  1928.   DEF gad:PTR TO gadget
  1929.   IF gh.wnd
  1930.     gad:=gh.glist
  1931.     WHILE gad
  1932.       IF gad.userdata=list THEN RETURN gad
  1933.       gad:=gad.nextgadget
  1934.     ENDWHILE
  1935.   ENDIF
  1936. ENDPROC NIL
  1937.  
  1938. #ifdef EASY_APPWINDOW
  1939. -> Search for gadget desc list based on mouse position.
  1940. PROC findxy(gh:PTR TO guihandle,x,y)
  1941.   DEF gad:PTR TO gadget,offx=0,offy=0
  1942.   gad:=gh.glist
  1943.   WHILE gad
  1944.     IF gad.mutualexclude=EG_MAGIC  -> Then it's an EasyGUI AppW gadget...
  1945.       -> The only gadgets (so far) have a label on the left or the top,
  1946.       -> so compensate and calculate the offset.
  1947.       IF gad.gadgettext
  1948.         offx:=gad.gadgettext.leftedge
  1949.         IF offx>0 THEN offx:=0
  1950.         offy:=gad.gadgettext.topedge
  1951.         IF offy>0 THEN offy:=0
  1952.       ENDIF
  1953.       IF x>=(gad.leftedge+offx) THEN
  1954.       IF y>=(gad.topedge+offy) THEN
  1955.       IF gad.leftedge+gad.width>x THEN
  1956.       IF gad.topedge+gad.height>y THEN RETURN gad.userdata
  1957.     ENDIF
  1958.     gad:=gad.nextgadget
  1959.   ENDWHILE
  1960. ENDPROC NIL
  1961. #endif
  1962.  
  1963. -> Set gadget attribute based on real gadget.
  1964. PROC setgadattr(g,w,gad:PTR TO LONG,value,tag,index=0)
  1965.   IF g THEN Gt_SetGadgetAttrsA(g,w,NIL,[tag,value,NIL])
  1966.   IF index THEN ATTR(gad,index):=value
  1967. ENDPROC
  1968.  
  1969. -> Set gadget attribute based on gadget desc list.
  1970. PROC setattr(gh:PTR TO guihandle,gad,value,tag,index=0) IS
  1971.   setgadattr(findgadget(gh,gad),gh.wnd,gad,value,tag,index)
  1972.  
  1973. /********** setXXXXX **********/
  1974. EXPORT PROC setcheck(gh,gad,bool) IS setattr(gh,gad,bool,GTCB_CHECKED,CHK_VAL)
  1975. EXPORT PROC setinteger(gh,gad,new) IS setattr(gh,gad,new,GTIN_NUMBER,INT_VAL)
  1976. EXPORT PROC setmx(gh,gad,active) IS setattr(gh,gad,active,GTMX_ACTIVE,MX_CURR)
  1977. EXPORT PROC setcycle(gh,gad,active) IS setattr(gh,gad,active,GTCY_ACTIVE,CYC_CURR)
  1978. EXPORT PROC setpalette(gh,gad,colour) IS setattr(gh,gad,colour,GTPA_COLOR,PAL_CURR)
  1979. EXPORT PROC setscrolltop(gh,gad,top) IS setattr(gh,gad,top,GTSC_TOP,SCR_TOP)
  1980. EXPORT PROC setscrolltotal(gh,gad,total) IS setattr(gh,gad,total,GTSC_TOTAL,SCR_TOTL)
  1981. EXPORT PROC setscrollvisible(gh,gad,visible) IS setattr(gh,gad,visible,GTSC_VISIBLE,SCR_VIS)
  1982. EXPORT PROC setslide(gh,gad,new) IS setattr(gh,gad,new,GTSL_LEVEL,SLI_CURR)
  1983. EXPORT PROC settext(gh,gad,new) IS setattr(gh,gad,new,GTTX_TEXT,TXT_VAL)
  1984. EXPORT PROC setnum(gh,gad,new) IS setattr(gh,gad,new,GTNM_NUMBER,NUM_VAL)
  1985. EXPORT PROC setlistvlabels(gh,gad,labs) IS setattr(gh,gad,labs,GTLV_LABELS,LST_LIST)
  1986. EXPORT PROC setlistvvisible(gh:PTR TO guihandle,gad,vis) IS setattr(gh,gad,vis,GTLV_MAKEVISIBLE)
  1987.  
  1988. EXPORT PROC setlistvselected(gh:PTR TO guihandle,gad,active)
  1989.   DEF g
  1990.   setgadattr(g:=findgadget(gh,gad),gh.wnd,gad,active,GTLV_SELECTED,LST_CURR)
  1991.   IF active<>-1 THEN setgadattr(g,gh.wnd,gad,active,GTLV_MAKEVISIBLE)
  1992. ENDPROC
  1993.  
  1994. EXPORT PROC setstr(gh,gad:PTR TO LONG,new)
  1995.   setattr(gh,gad,new,GTST_STRING)
  1996. ENDPROC StrCopy(ATTR(gad,STR_STR),new)
  1997.  
  1998. /********** disposegui **********/
  1999. EXPORT PROC disposegui(gui:PTR TO LONG)
  2000.   DEF a,l
  2001.   IF gui
  2002.     IF IsGroup(ATTR(gui,EG_TYPE))
  2003.       l:=ListLen(gui)-1
  2004.       FOR a:=1 TO l DO disposegui(gui[a])
  2005.     ENDIF
  2006.     FastDisposeList(gui)
  2007.   ENDIF
  2008. ENDPROC
  2009.